给定一个由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 < r并且集合的大小大于K 时迭代:
- 如果mp[arr[r]]等于1 ,则减少mp中arr[l]的计数,然后从集合S 中删除元素。
- 将cntSub和l增加1 。
- 在r小于N且集合的大小至多为 K 时进行迭代:
- 现在迭代l < N并且集合的大小为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 occurring twice
int cntSubarrays(int A[], int K, int n)
{
// Stores the count of subarrays
// having exactly K elements
// occurring 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 occurring twice
static int cntSubarrays(int[] A, int K, int n)
{
// Stores the count of subarrays
// having exactly K elements
// occurring 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 occurring twice
def cntSubarrays(A, K, n):
# Stores the count of subarrays
# having exactly K elements
# occurring 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 occurring twice
static int cntSubarrays(int []A, int K, int n)
{
// Stores the count of subarrays
// having exactly K elements
// occurring 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.
Javascript
输出:
7
时间复杂度: O(N*log N)
辅助空间: O(N)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。