给定一个大小为 n 的数组和一个整数 k,返回所有大小为 k 的窗口中不同数字的计数。
例子:
Input: arr[] = {1, 2, 1, 3, 4, 2, 3};
k = 4
Output: 3 4 4 3
Explanation:
First window is {1, 2, 1, 3}, count of distinct numbers is 3
Second window is {2, 1, 3, 4} count of distinct numbers is 4
Third window is {1, 3, 4, 2} count of distinct numbers is 4
Fourth window is {3, 4, 2, 3} count of distinct numbers is 3
Input: arr[] = {1, 2, 4, 4};
k = 2
Output: 2 2 1
Explanation:
First window is {1, 2}, count of distinct numbers is 2
First window is {2, 4}, count of distinct numbers is 2
First window is {4, 4}, count of distinct numbers is 1
来源:这个问题出现在微软面试题中。
朴素的方法:朴素的解决方案是遍历给定的数组,考虑其中的每个窗口,并保持对窗口不同元素的计数。
算法:
- 对于从 0 到 len_array(n) – k 的每个索引 i,即n – k ,从i到i + k遍历数组。这是窗户
- 遍历窗口,从i到该索引并检查元素是否存在。
- 如果该元素不存在于数组的前缀中,即从i到index-1不存在重复元素,则增加计数。
- 打印计数。
下面是上述方法的实现:
C++
// Simple C++ program to count distinct
// elements in every window of size k
#include
using namespace std;
// Counts distinct elements in window of size k
int countWindowDistinct(int win[], int k)
{
int dist_count = 0;
// Traverse the window
for (int i = 0; i < k; i++) {
// Check if element arr[i] exists in arr[0..i-1]
int j;
for (j = 0; j < i; j++)
if (win[i] == win[j])
break;
if (j == i)
dist_count++;
}
return dist_count;
}
// Counts distinct elements in all windows of size k
void countDistinct(int arr[], int n, int k)
{
// Traverse through every window
for (int i = 0; i <= n - k; i++)
cout << countWindowDistinct(arr + i, k) << endl;
}
// Driver program
int main()
{
int arr[] = { 1, 2, 1, 3, 4, 2, 3 }, k = 4;
int n = sizeof(arr) / sizeof(arr[0]);
countDistinct(arr, n, k);
return 0;
}
Java
// Simple Java program to count distinct elements in every
// window of size k
import java.util.Arrays;
class Test {
// Counts distinct elements in window of size k
static int countWindowDistinct(int win[], int k)
{
int dist_count = 0;
// Traverse the window
for (int i = 0; i < k; i++) {
// Check if element arr[i] exists in arr[0..i-1]
int j;
for (j = 0; j < i; j++)
if (win[i] == win[j])
break;
if (j == i)
dist_count++;
}
return dist_count;
}
// Counts distinct elements in all windows of size k
static void countDistinct(int arr[], int n, int k)
{
// Traverse through every window
for (int i = 0; i <= n - k; i++)
System.out.println(countWindowDistinct(Arrays.copyOfRange(arr, i, arr.length), k));
}
// Driver method
public static void main(String args[])
{
int arr[] = { 1, 2, 1, 3, 4, 2, 3 }, k = 4;
countDistinct(arr, arr.length, k);
}
}
Python3
# Simple Python3 program to count distinct
# elements in every window of size k
import math as mt
# Counts distinct elements in window
# of size k
def countWindowDistinct(win, k):
dist_count = 0
# Traverse the window
for i in range(k):
# Check if element arr[i] exists
# in arr[0..i-1]
j = 0
while j < i:
if (win[i] == win[j]):
break
else:
j += 1
if (j == i):
dist_count += 1
return dist_count
# Counts distinct elements in all
# windows of size k
def countDistinct(arr, n, k):
# Traverse through every window
for i in range(n - k + 1):
print(countWindowDistinct(arr[i:k + i], k))
# Driver Code
arr = [1, 2, 1, 3, 4, 2, 3]
k = 4
n = len(arr)
countDistinct(arr, n, k)
# This code is contributed by
# Mohit kumar 29
C#
// Simple C# program to count distinct
// elements in every window of size k
using System;
using System.Collections.Generic;
class GFG {
// Counts distinct elements in
// window of size k
static int countWindowDistinct(int[] win,
int k)
{
int dist_count = 0;
// Traverse the window
for (int i = 0; i < k; i++) {
// Check if element arr[i]
// exists in arr[0..i-1]
int j;
for (j = 0; j < i; j++)
if (win[i] == win[j])
break;
if (j == i)
dist_count++;
}
return dist_count;
}
// Counts distinct elements in
// all windows of size k
static void countDistinct(int[] arr,
int n, int k)
{
// Traverse through every window
for (int i = 0; i <= n - k; i++) {
int[] newArr = new int[k];
Array.Copy(arr, i, newArr, 0, k);
Console.WriteLine(countWindowDistinct(newArr, k));
}
}
// Driver Code
public static void Main(String[] args)
{
int[] arr = { 1, 2, 1, 3, 4, 2, 3 };
int k = 4;
countDistinct(arr, arr.Length, k);
}
}
// This code is contributed by Princi Singh
Javascript
C++
// An efficient C++ program to
// count distinct elements in
// every window of size k
#include
#include
using namespace std;
void countDistinct(int arr[], int k, int n)
{
// Creates an empty hashmap hm
unordered_map hm;
// initialize distinct element count for current window
int dist_count = 0;
// Traverse the first window and store count
// of every element in hash map
for (int i = 0; i < k; i++) {
if (hm[arr[i]] == 0) {
dist_count++;
}
hm[arr[i]] += 1;
}
// Print count of first window
cout << dist_count << endl;
// Traverse through the remaining array
for (int i = k; i < n; i++) {
// Remove first element of previous window
// If there was only one occurrence, then reduce distinct count.
if (hm[arr[i - k]] == 1) {
dist_count--;
}
// reduce count of the removed element
hm[arr[i - k]] -= 1;
// Add new element of current window
// If this element appears first time,
// increment distinct element count
if (hm[arr[i]] == 0) {
dist_count++;
}
hm[arr[i]] += 1;
// Print count of current window
cout << dist_count << endl;
}
}
int main()
{
int arr[] = { 1, 2, 1, 3, 4, 2, 3 };
int size = sizeof(arr) / sizeof(arr[0]);
int k = 4;
countDistinct(arr, k, size);
return 0;
}
// This solution is contributed by Aditya Goel
Java
// An efficient Java program to count distinct elements in
// every window of size k
import java.util.HashMap;
class CountDistinctWindow {
static void countDistinct(int arr[], int k)
{
// Creates an empty hashMap hM
HashMap hM = new HashMap();
// Traverse the first window and store count
// of every element in hash map
for (int i = 0; i < k; i++)
hM.put(arr[i], hM.getOrDefault(arr[i], 0) + 1);
// Print count of first window
System.out.println(hM.size());
// Traverse through the remaining array
for (int i = k; i < arr.length; i++) {
// Remove first element of previous window
// If there was only one occurrence
if (hM.get(arr[i - k]) == 1) {
hM.remove(arr[i - k]);
}
else // reduce count of the removed element
hM.put(arr[i - k], hM.get(arr[i - k]) - 1);
// Add new element of current window
// If this element appears first time,
// set its count as 1,
hM.put(arr[i], hM.getOrDefault(arr[i], 0) + 1);
// Print count of current window
System.out.println(hM.size());
}
}
// Driver method
public static void main(String arg[])
{
int arr[] = { 1, 2, 1, 3, 4, 2, 3 };
int k = 4;
countDistinct(arr, k);
}
}
Python3
# An efficient Python program to
# count distinct elements in
# every window of size k
from collections import defaultdict
def countDistinct(arr, k, n):
# Creates an empty hashmap hm
mp = defaultdict(lambda:0)
# initialize distinct element
# count for current window
dist_count = 0
# Traverse the first window and store count
# of every element in hash map
for i in range(k):
if mp[arr[i]] == 0:
dist_count += 1
mp[arr[i]] += 1
# Print count of first window
print(dist_count)
# Traverse through the remaining array
for i in range(k, n):
# Remove first element of previous window
# If there was only one occurrence,
# then reduce distinct count.
if mp[arr[i - k]] == 1:
dist_count -= 1
mp[arr[i - k]] -= 1
# Add new element of current window
# If this element appears first time,
# increment distinct element count
if mp[arr[i]] == 0:
dist_count += 1
mp[arr[i]] += 1
# Print count of current window
print(dist_count)
arr = [1, 2, 1, 3, 4, 2, 3]
n = len(arr)
k = 4
countDistinct(arr, k, n)
# This code is contributed by Shrikant13
C#
// An efficient C# program to count
// distinct elements in every window of size k
using System;
using System.Collections.Generic;
public class CountDistinctWindow {
static void countDistinct(int[] arr, int k)
{
// Creates an empty hashMap hM
Dictionary hM = new Dictionary();
// initialize distinct element count for
// current window
int dist_count = 0;
// Traverse the first window and store count
// of every element in hash map
for (int i = 0; i < k; i++) {
if (!hM.ContainsKey(arr[i])) {
hM.Add(arr[i], 1);
dist_count++;
}
else {
int count = hM[arr[i]];
hM.Remove(arr[i]);
hM.Add(arr[i], count + 1);
}
}
// Print count of first window
Console.WriteLine(dist_count);
// Traverse through the remaining array
for (int i = k; i < arr.Length; i++) {
// Remove first element of previous window
// If there was only one occurrence, then
// reduce distinct count.
if (hM[arr[i - k]] == 1) {
hM.Remove(arr[i - k]);
dist_count--;
}
else // reduce count of the removed element
{
int count = hM[arr[i - k]];
hM.Remove(arr[i - k]);
hM.Add(arr[i - k], count - 1);
}
// Add new element of current window
// If this element appears first time,
// increment distinct element count
if (!hM.ContainsKey(arr[i])) {
hM.Add(arr[i], 1);
dist_count++;
}
else // Increment distinct element count
{
int count = hM[arr[i]];
hM.Remove(arr[i]);
hM.Add(arr[i], count + 1);
}
// Print count of current window
Console.WriteLine(dist_count);
}
}
// Driver method
public static void Main(String[] arg)
{
int[] arr = { 1, 2, 1, 3, 4, 2, 3 };
int k = 4;
countDistinct(arr, k);
}
}
// This code contributed by Rajput-Ji
输出
3
4
4
3
复杂度分析:
- 时间复杂度: O(nk 2 )。
通过使用排序修改 countWindowDistinct() 可以将时间复杂度提高到O(n*k*log k) 。该函数可以进一步优化以使用散列来查找窗口中的不同元素。通过散列,时间复杂度变为O(n*k) 。 - 空间复杂度:O(1)我们不需要任何额外的空间。
高效的方法:所以,有一个使用散列的有效解决方案,虽然散列需要额外的O(n)空间,但时间复杂度会提高。诀窍是在滑动窗口时使用前一个窗口的计数。为此,可以使用散列映射来存储当前窗口的元素。哈希映射还通过同时添加和删除元素来操作,同时跟踪不同的元素。该问题涉及在移动窗口的任何步骤中找到长度为k的窗口中不同元素的计数并丢弃在前一步中完成的所有计算,即使k – 1 个元素与前一个相邻窗口相同。例如,假设从索引i到i + k – 1的元素作为元素频率对存储在哈希图中。因此,在更新i + 1到i + k范围内的哈希映射时,将第i 个元素的频率减少 1,并将第(i + k) 个元素的频率增加 1。
从 HashMap 插入和删除需要恒定的时间。
- 算法:
- 创建一个空的哈希映射。让哈希映射为hM 。
- 将不同元素的计数作为dist_count初始化为 0。
- 遍历第一个窗口并将第一个窗口的元素插入到hM 中。这些元素用作键,它们的计数作为 hM 中的值。另外,不断更新dist_count
- 打印第一个窗口的不同计数。
- 遍历剩余的数组(或其他窗口)。
- 删除前一个窗口的第一个元素。
- 如果删除的元素只出现一次,从hM 中删除它并减少不同的计数,即执行“dist_count-”
- 否则(在 hM 中出现多次),然后在 hM 中减少其计数
- 添加当前元素(新窗口的最后一个元素)
- 如果添加的元素在 hM 中不存在,则将其添加到hM并增加不同的计数,即执行“dist_count++”
- 否则(添加的元素出现多次),以hM 为单位增加其计数
- 以下是上述方法的试运行:
- 执行:
C++
// An efficient C++ program to
// count distinct elements in
// every window of size k
#include
#include
using namespace std;
void countDistinct(int arr[], int k, int n)
{
// Creates an empty hashmap hm
unordered_map hm;
// initialize distinct element count for current window
int dist_count = 0;
// Traverse the first window and store count
// of every element in hash map
for (int i = 0; i < k; i++) {
if (hm[arr[i]] == 0) {
dist_count++;
}
hm[arr[i]] += 1;
}
// Print count of first window
cout << dist_count << endl;
// Traverse through the remaining array
for (int i = k; i < n; i++) {
// Remove first element of previous window
// If there was only one occurrence, then reduce distinct count.
if (hm[arr[i - k]] == 1) {
dist_count--;
}
// reduce count of the removed element
hm[arr[i - k]] -= 1;
// Add new element of current window
// If this element appears first time,
// increment distinct element count
if (hm[arr[i]] == 0) {
dist_count++;
}
hm[arr[i]] += 1;
// Print count of current window
cout << dist_count << endl;
}
}
int main()
{
int arr[] = { 1, 2, 1, 3, 4, 2, 3 };
int size = sizeof(arr) / sizeof(arr[0]);
int k = 4;
countDistinct(arr, k, size);
return 0;
}
// This solution is contributed by Aditya Goel
Java
// An efficient Java program to count distinct elements in
// every window of size k
import java.util.HashMap;
class CountDistinctWindow {
static void countDistinct(int arr[], int k)
{
// Creates an empty hashMap hM
HashMap hM = new HashMap();
// Traverse the first window and store count
// of every element in hash map
for (int i = 0; i < k; i++)
hM.put(arr[i], hM.getOrDefault(arr[i], 0) + 1);
// Print count of first window
System.out.println(hM.size());
// Traverse through the remaining array
for (int i = k; i < arr.length; i++) {
// Remove first element of previous window
// If there was only one occurrence
if (hM.get(arr[i - k]) == 1) {
hM.remove(arr[i - k]);
}
else // reduce count of the removed element
hM.put(arr[i - k], hM.get(arr[i - k]) - 1);
// Add new element of current window
// If this element appears first time,
// set its count as 1,
hM.put(arr[i], hM.getOrDefault(arr[i], 0) + 1);
// Print count of current window
System.out.println(hM.size());
}
}
// Driver method
public static void main(String arg[])
{
int arr[] = { 1, 2, 1, 3, 4, 2, 3 };
int k = 4;
countDistinct(arr, k);
}
}
蟒蛇3
# An efficient Python program to
# count distinct elements in
# every window of size k
from collections import defaultdict
def countDistinct(arr, k, n):
# Creates an empty hashmap hm
mp = defaultdict(lambda:0)
# initialize distinct element
# count for current window
dist_count = 0
# Traverse the first window and store count
# of every element in hash map
for i in range(k):
if mp[arr[i]] == 0:
dist_count += 1
mp[arr[i]] += 1
# Print count of first window
print(dist_count)
# Traverse through the remaining array
for i in range(k, n):
# Remove first element of previous window
# If there was only one occurrence,
# then reduce distinct count.
if mp[arr[i - k]] == 1:
dist_count -= 1
mp[arr[i - k]] -= 1
# Add new element of current window
# If this element appears first time,
# increment distinct element count
if mp[arr[i]] == 0:
dist_count += 1
mp[arr[i]] += 1
# Print count of current window
print(dist_count)
arr = [1, 2, 1, 3, 4, 2, 3]
n = len(arr)
k = 4
countDistinct(arr, k, n)
# This code is contributed by Shrikant13
C#
// An efficient C# program to count
// distinct elements in every window of size k
using System;
using System.Collections.Generic;
public class CountDistinctWindow {
static void countDistinct(int[] arr, int k)
{
// Creates an empty hashMap hM
Dictionary hM = new Dictionary();
// initialize distinct element count for
// current window
int dist_count = 0;
// Traverse the first window and store count
// of every element in hash map
for (int i = 0; i < k; i++) {
if (!hM.ContainsKey(arr[i])) {
hM.Add(arr[i], 1);
dist_count++;
}
else {
int count = hM[arr[i]];
hM.Remove(arr[i]);
hM.Add(arr[i], count + 1);
}
}
// Print count of first window
Console.WriteLine(dist_count);
// Traverse through the remaining array
for (int i = k; i < arr.Length; i++) {
// Remove first element of previous window
// If there was only one occurrence, then
// reduce distinct count.
if (hM[arr[i - k]] == 1) {
hM.Remove(arr[i - k]);
dist_count--;
}
else // reduce count of the removed element
{
int count = hM[arr[i - k]];
hM.Remove(arr[i - k]);
hM.Add(arr[i - k], count - 1);
}
// Add new element of current window
// If this element appears first time,
// increment distinct element count
if (!hM.ContainsKey(arr[i])) {
hM.Add(arr[i], 1);
dist_count++;
}
else // Increment distinct element count
{
int count = hM[arr[i]];
hM.Remove(arr[i]);
hM.Add(arr[i], count + 1);
}
// Print count of current window
Console.WriteLine(dist_count);
}
}
// Driver method
public static void Main(String[] arg)
{
int[] arr = { 1, 2, 1, 3, 4, 2, 3 };
int k = 4;
countDistinct(arr, k);
}
}
// This code contributed by Rajput-Ji
输出
3
4
4
3
- 复杂度分析:
- 时间复杂度O(n)。因为需要单次遍历数组。
- 空间复杂度O(n)。因为,哈希图需要线性空间。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。