📌  相关文章
📜  计算每个大小为 k 的窗口中的不同元素

📅  最后修改于: 2021-10-27 08:23:04             🧑  作者: Mango

给定一个大小为 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
 

来源:这个问题出现在微软面试题中。
朴素的方法:朴素的解决方案是遍历给定的数组,考虑其中的每个窗口,并保持对窗口不同元素的计数。

算法:

  1. 对于从 0 到 len_array(n) – k 的每个索引 i,即n – k ,从ii + k遍历数组。这是窗户
  2. 遍历窗口,从i到该索引并检查元素是否存在。
  3. 如果该元素不存在于数组的前缀中,即从iindex-1不存在重复元素,则增加计数。
  4. 打印计数。

下面是上述方法的实现:

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 个元素与前一个相邻窗口相同。例如,假设从索引ii + k – 1的元素作为元素频率对存储在哈希图中。因此,在更新i + 1i + k范围内的哈希映射时,将第i 个元素的频率减少 1,并将第(i + k) 个元素的频率增加 1。
从 HashMap 插入和删除需要恒定的时间。

  • 算法:
    1. 创建一个空的哈希映射。让哈希映射为hM
    2. 将不同元素的计数作为dist_count初始化为 0。
    3. 遍历第一个窗口并将第一个窗口的元素插入到hM 中。这些元素用作键,它们的计数作为 hM 中的值。另外,不断更新dist_count
    4. 打印第一个窗口的不同计数。
    5. 遍历剩余的数组(或其他窗口)。
    6. 删除前一个窗口的第一个元素。
      • 如果删除的元素只出现一次,从hM 中删除它并减少不同的计数,即执行“dist_count-”
      • 否则(在 hM 中出现多次),然后在 hM 中减少其计数
    7. 添加当前元素(新窗口的最后一个元素)
      • 如果添加的元素在 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 现场工作专业课程学生竞争性编程现场课程