1

The question is: "Given an array A only contains integers Return the number of subarrays that contain at least k different numbers. Subarrays cannot be duplicated."

Example:

input array = {1, 2, 3, 4, 2} k = 3

output: 4

Explanation:

the number of the Subarray with at least K different numbers should be 4, which are [1, 2, 3] [2, 3, 4] [3, 4, 2] [1, 2, 3, 4]

Right now what I can do is just find about the number of the subarray with exactly K different numbers:

class Solution {
    public int subarraysWithKDistinct(int[] A, int K) {
        return atMostK(A, K) - atMostK(A, K - 1);
    }
    
    private int atMostK(int[] A, int K) {
        int i = 0, res = 0;
        
        Map<Integer, Integer> count = new HashMap<>();
        
        for (int j = 0; j < A.length; ++j) {
            
            if (count.getOrDefault(A[j], 0) == 0) K--;
            count.put(A[j], count.getOrDefault(A[j], 0) + 1);
            
            while (K < 0) {
                count.put(A[i], count.get(A[i]) - 1);
                if (count.get(A[i]) == 0) K++;
                i++;
            
            }
            res += j - i + 1;
        }
        
        return res;
    }
}

But when the input be: array = {1, 2, 3, 4, 2} k = 2 my code will not work correctly, but I don't know where to change. Any thoughts? Thanks!

Update: thanks to @MBo and others' answers, I used 2 pointers to fix this problem, but still cannot get the right answer with: array = {1, 2, 3, 4, 2} k = 3 -> output: 6 (should be 4)

It looks like there are some duplicated substrings be counted, but I don't know how to fix it.

class Solution {
    public static void main(String[] args) {
        int[] A = {1, 2, 3, 4, 2};
        int k = 3;
        int res = helper(A, k);
        System.out.println(res);
        // output is 6, but should be 4
    }
    
    private static int helper(int[] A, int k) {
        if (A == null || A.length == 0) return 0;
    
        int n = A.length;
        int res = 0;
        int differentNumbers = 0;

        Map<Integer, Integer> counter = new HashMap<>();
        int j = 0;  // j - 1 is the right point


        for (int i = 0; i < n; i ++) {
            while (j < n && differentNumbers < k) {
                int numOfThisNumber = counter.getOrDefault(A[j], 0);
                counter.put(A[j], numOfThisNumber + 1);
                if (counter.get(A[j]) == 1) {
                    differentNumbers ++;
                }
                j ++;
            }
            if (differentNumbers == k) {
                res += n - j + 1;
            }

            counter.put(A[i], counter.get(A[i]) - 1);
            if (counter.get(A[i]) == 0) {
                differentNumbers --;
            }
        }
        return res; 
    }
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
heheNhaha
  • 25
  • 1
  • 6
  • Hint: Try computing the number of such subarrays *that end at position i*, for each i. These can be added together without double-counting or missing solutions. – j_random_hacker May 19 '21 at 09:08
  • The count should actually be 5, since {1,2,3,4,2} is a subarray of itself and does contain 3 unique numbers, unless you add the condition that subarrays contain no duplicate values. In that case, the result is computable with simple binomial coefficients: let `u` be the number of unique values, your result is the sum of all arrangements of `k` to `u` items drawn from a set of length u, i.e. the sum of `(i!)/((i-k!)(k!))` for `i` in `[k..u]` If you count duplicates, then your example should include {1,2,3,4,2} in the list and the expected result should be corrected. – kuroi neko May 19 '21 at 10:38
  • Emm... Statement `Subarray with at least K different numbers` does not claim that duplicate values are not allowed inside subarray. Could you show exact problem formulation? – MBo May 20 '21 at 09:16
  • Sure, sorry about the unclear question. I also updated the topic. The question is "Given an array A only contains integers Return the number of subarrays that contain at least k different numbers. Subarrays cannot be duplicated." It is my professor's in-class pop-quiz last week, and I tried to look up leetcode or hackerrank, cannot find similar problems – heheNhaha May 20 '21 at 22:43

1 Answers1

4

You can combine your hashmap approach with method of two pointers (indices).

Set both indices into 0 and move right one, updating hashmap counts for values at the right end of interval until hashmap size reaches K. Fix right index.

Now move left index, decreasing counts corresponding to the values at left end. Before every step (including left=0) add size-right to result, because all subarrays starting from left and ending after right, do contain needed number of elements.

When some count becomes 0, remove value from hashmap, and fix left index.

Repeat with right index and so on.

MBo
  • 77,366
  • 5
  • 53
  • 86