给定一个由N个整数和一个正整数K组成的数组arr [] ,任务是计算具有正好K个元素至少出现两次的子数组的数量。
例子:
Input: arr[] = {1, 1, 1, 2, 2}, K = 1
Output: 7
Explanation: The subarrays having exactly 1 element occurring at least twice are:
- {1, 1}. Frequency of 1 is 2.
- {1, 1, 1}. Frequency of 1 is 3.
- {1, 1, 1, 2}. Frequency of 1 is 3.
- {1, 1}. Frequency of 1 is 2.
- {1, 1, 2}. Frequency of 1 is 2.
- {1, 2, 2}. Frequency of 2 is 2.
- {2, 2}. Frequency of 2 is 2.
Therefore, the required output is 7.
Input: arr[] = {1, 2, 1, 2, 3}, K = 3
Output: 0
天真的方法:解决此问题的最简单方法是从给定数组生成所有可能的子数组 并计算至少有两次恰好有K个元素的子数组。检查完所有子阵列后,打印获得的子阵列总数。
时间复杂度: O(N 3 )
辅助空间: O(N)
高效的方法:可以通过使用哈希和两个指针技术来优化上述方法。请按照以下步骤解决问题:
- 初始化一个变量,例如cntSub为0 ,以存储所有K元素至少出现两次的所有可能子数组的计数。
- 初始化两个变量,将l设为0 ,将r设为0 ,以分别存储每个子数组的左边界和右边界的索引。
- 初始化一个Map(例如mp )和一个Set(例如S)以将元素计数存储在子数组中,并存储其频率至少为2的元素。
- 迭代直到r小于N并执行以下操作:
- 当r小于N且集合的大小最大为K时进行迭代:
- 如果mp [arr [r]]等于2 ,则以mp为单位增加arr [r]的计数,然后将其推入集合S中。
- 将r递增1 。
- 如果集合S的大小为K ,则将cntSub增大1 。
- 当l
并且集合的大小大于K时进行迭代: - 如果mp [arr [r]]等于1 ,则以mp为单位减少arr [l]的计数,然后从集合S中删除该元素。
- 将cntSub和l加1 。
- 当r小于N且集合的大小最大为K时进行迭代:
- 现在,当l
且集合的大小为K时进行迭代,并将arr [l]的计数减1 ,如果arr [l]的频率为1 ,则从集合中删除arr [l] 。 - 完成上述步骤后,打印cntSub的值作为子数组的结果计数。
下面是上述方法的实现:
C++14
// C++ program for the above approach
#include
using namespace std;
// Function to count the subarrays with
// exactly K elements occuring twice
int cntSubarrays(int A[], int K, int n)
{
// Stores the count of subarrays
// having exactly K elements
// occuring at least twice
int cntSub = 0;
// Stores the count of
// integers in the subarray
map mp;
// Stores the indices of left
// boundary and right boundary
int l = 0, r = 0;
// Store the elements which occurs
// atleast twice between [l, r]
set st;
// Iterate while r < n
while (r < n) {
// Iterate while r < n
// and size of st <= K
while (r < n && st.size() <= K) {
// If mp[A[r]] >= 1
if (mp[A[r]]) {
st.insert(A[r]);
}
// Increment count of A[r]
mp[A[r]]++;
// Increment r by 1
r++;
// If st.size() is K
if (st.size() == K)
cntSub++;
}
// Iterate while l < r
// and st.size() > K
while (l < r && st.size() > K) {
// Increment cntSub by 1
cntSub++;
// Decrement cntSub by 1
mp[A[l]]--;
// If mp[A[l]] = 1
if (mp[A[l]] == 1) {
st.erase(st.find(A[l]));
}
// Increment l by 1
l++;
}
}
// Iterate while l < n and
// st.size() == K
while (l < n && st.size() == K) {
// Increment cntSub by 1
cntSub++;
mp[A[l]]--;
// If Mp[A[l]] is equal to 1
if (mp[A[l]] == 1) {
st.erase(st.find(A[l]));
}
// Increment l by 1
l++;
}
// Return cntSub
return cntSub;
}
// Driver Code
int main()
{
int arr[] = { 1, 1, 1, 2, 2 };
int K = 1;
int N = sizeof(arr) / sizeof(arr[0]);
cout << cntSubarrays(arr, K, N);
return 0;
}
Java
// Java program for the above approach
import java.util.*;
class GFG {
// Function to count the subarrays with
// exactly K elements occuring twice
static int cntSubarrays(int[] A, int K, int n)
{
// Stores the count of subarrays
// having exactly K elements
// occuring at least twice
int cntSub = 0;
// Stores the count of
// integers in the subarray
HashMap mp
= new HashMap();
// Stores the indices of left
// boundary and right boundary
int l = 0, r = 0;
// Store the elements which occurs
// atleast twice between [l, r]
HashSet st = new HashSet();
// Iterate while r < n
while (r < n) {
// Iterate while r < n
// and size of st <= K
while (r < n && st.size() <= K) {
// If mp[A[r]] >= 1
if (mp.containsKey(A[r])) {
st.add(A[r]);
}
// Increment count of A[r]
if (mp.containsKey(A[r]))
mp.put(A[r], mp.get(A[r]) + 1);
else
mp.put(A[r], 1);
// Increment r by 1
r++;
// If st.size() is K
if (st.size() == K)
cntSub++;
}
// Iterate while l < r
// and st.size() > K
while (l < r && st.size() > K) {
// Increment cntSub by 1
cntSub++;
// Decrement cntSub by 1
if (mp.containsKey(A[l]))
mp.put(A[l], mp.get(A[l]) - 1);
// If mp[A[l]] = 1
if (mp.get(A[l]) == 1) {
st.remove(A[l]);
}
// Increment l by 1
l++;
}
}
// Iterate while l < n and
// st.size() == K
while (l < n && st.size() == K) {
// Increment cntSub by 1
cntSub++;
if (mp.containsKey(A[l]))
mp.put(A[l], mp.get(A[l]) - 1);
// If Mp[A[l]] is equal to 1
if (mp.get(A[l]) == 1) {
st.remove(A[l]);
}
// Increment l by 1
l++;
}
// Return cntSub
return cntSub;
}
// Driver Code
public static void main(String[] args)
{
int[] arr = { 1, 1, 1, 2, 2 };
int K = 1;
int N = arr.length;
System.out.println(cntSubarrays(arr, K, N));
}
}
// This code is contributed by ukasp.
Python3
# Python3 program for the above approach
# Function to count the subarrays with
# exactly K elements occuring twice
def cntSubarrays(A, K, n):
# Stores the count of subarrays
# having exactly K elements
# occuring at least twice
cntSub = 0
# Stores the count of
# integers in the subarray
mp = {}
# Stores the indices of left
# boundary and right boundary
l = 0
r = 0
# Store the elements which occurs
# atleast twice between [l, r]
st = set()
# Iterate while r < n
while (r < n):
# Iterate while r < n
# and size of st <= K
while (r < n and len(st) <= K):
# If mp[A[r]] >= 1
if (A[r] in mp):
st.add(A[r])
# Increment count of A[r]
if (A[r] in mp):
mp[A[r]] += 1
else:
mp[A[r]] = 1
# Increment r by 1
r += 1
# If st.size() is K
if (len(st) == K):
cntSub += 1
# Iterate while l < r
# and st.size() > K
while (l < r and len(st) > K):
# Increment cntSub by 1
cntSub += 1
# Decrement cntSub by 1
if (A[l] in mp):
mp[A[l]] -= 1
else:
mp[A[l]] = 1
# If mp[A[l]] = 1
if (mp[A[l]] == 1):
st.remove(A[l])
# Increment l by 1
l += 1
# Iterate while l < n and
# st.size() == K
while (l < n and len(st) == K):
# Increment cntSub by 1
cntSub += 1
mp[A[l]] -= 1
# If Mp[A[l]] is equal to 1
if (mp[A[l]] == 1):
st.remove(A[l])
# Increment l by 1
l += 1
# Return cntSub
return cntSub
# Driver Code
if __name__ == '__main__':
arr = [1, 1, 1, 2, 2]
K = 1
N = len(arr)
print(cntSubarrays(arr, K, N))
# This code is contributed by ipg2016107
C#
// C# program for the above approach
using System;
using System.Collections.Generic;
class GFG{
// Function to count the subarrays with
// exactly K elements occuring twice
static int cntSubarrays(int []A, int K, int n)
{
// Stores the count of subarrays
// having exactly K elements
// occuring at least twice
int cntSub = 0;
// Stores the count of
// integers in the subarray
Dictionary mp = new Dictionary();
// Stores the indices of left
// boundary and right boundary
int l = 0, r = 0;
// Store the elements which occurs
// atleast twice between [l, r]
HashSet st = new HashSet();
// Iterate while r < n
while (r < n) {
// Iterate while r < n
// and size of st <= K
while (r < n && st.Count <= K) {
// If mp[A[r]] >= 1
if (mp.ContainsKey(A[r])) {
st.Add(A[r]);
}
// Increment count of A[r]
if (mp.ContainsKey(A[r]))
mp[A[r]]++;
else
mp[A[r]] = 1;
// Increment r by 1
r++;
// If st.size() is K
if (st.Count == K)
cntSub++;
}
// Iterate while l < r
// and st.size() > K
while (l < r && st.Count > K) {
// Increment cntSub by 1
cntSub++;
// Decrement cntSub by 1
if (mp.ContainsKey(A[l]))
mp[A[l]]--;
// If mp[A[l]] = 1
if (mp[A[l]] == 1) {
st.Remove(A[l]);
}
// Increment l by 1
l++;
}
}
// Iterate while l < n and
// st.size() == K
while (l < n && st.Count == K) {
// Increment cntSub by 1
cntSub++;
if (mp.ContainsKey(A[l]))
mp[A[l]]--;
// If Mp[A[l]] is equal to 1
if (mp[A[l]] == 1) {
st.Remove(A[l]);
}
// Increment l by 1
l++;
}
// Return cntSub
return cntSub;
}
// Driver Code
public static void Main()
{
int []arr = { 1, 1, 1, 2, 2 };
int K = 1;
int N = arr.Length;
Console.WriteLine(cntSubarrays(arr, K, N));
}
}
// This code is contributed by ipg2016107.
输出:
7
时间复杂度: O(N * log N)
辅助空间: O(N)