Distribute Repeating Integers

You are given an array of n integers, nums, where there are at most 50 unique values in the array. You are also given an array of m customer order quantities, quantity, where quantity[i] is the amount of integers the ith customer ordered. Determine if it is possible to distribute nums such that:

Return true if it is possible to distribute nums according to the above conditions.

 

Example 1:

Input: nums = [1,2,3,4], quantity = [2]
Output: false
Explanation: The 0th customer cannot be given two different integers.

Example 2:

Input: nums = [1,2,3,3], quantity = [2]
Output: true
Explanation: The 0th customer is given [3,3]. The integers [1,2] are not used.

Example 3:

Input: nums = [1,1,2,2], quantity = [2,2]
Output: true
Explanation: The 0th customer is given [1,1], and the 1st customer is given [2,2].

Example 4:

Input: nums = [1,1,2,3], quantity = [2,2]
Output: false
Explanation: Although the 0th customer could be given [1,1], the 1st customer cannot be satisfied.
Example 5:

Input: nums = [1,1,1,1,1], quantity = [2,3]
Output: true
Explanation: The 0th customer is given [1,1], and the 1st customer is given [1,1,1].

 

Constraints:


Solution:

class Solution {
    public boolean canDistribute(int[] nums, int[] quantity) {
        int[] count = new int[1001];
        TreeSet<Integer> set = new TreeSet(Collections.reverseOrder());
        for (int val : nums) {
            count[val] ++;
            set.add(val);
        }
        int[] c = new int[50];
        int i = 0;
        while (!set.isEmpty()) {
            c[i] = set.first();
            set.remove(c[i]);
            i ++;
        }
        Arrays.sort(quantity);
        return helper(c, count, quantity, quantity.length - 1);
    }
    
    private boolean helper(int[] c, int[] count, int[] quantity, int start) {
        if (start < 0) return true;
        for (int i = 0; i < 50; i ++) {
            int item = c[i];
            if (count[item] >= quantity[start]) {
                count[item] -= quantity[start];
                if (helper(c, count, quantity, start - 1)) {
                    return true;
                }
                count[item] += quantity[start];
            }
        }
        return false;
    }
}


dp[i][j] = for numbers in subsequence [0, i], whether it can satisfy j (bit mask of quantity)
class Solution {
    public boolean canDistribute(int[] nums, int[] quantity) {
        Map<Integer, Integer> count = new HashMap();
        for (int val : nums) {
            count.put(val, count.getOrDefault(val, 0) + 1);
        }
        List<Integer> items = new ArrayList(count.keySet());
        int n = items.size(), m = quantity.length;
        int[] requirements = new int[1 << m];
        for (int i = 0; i < (1 << m); i ++) {
            for (int j = 0; j < m; j ++) {
                if ((i & (1 << j)) > 0) {
                    requirements[i] += quantity[j];
                }
            }
        }

        boolean[][] dp = new boolean[n + 1][1 << m];
        dp[0][0] = true;
        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < (1 << m); j ++) {
                dp[i + 1][j] |= dp[i][j];
                for (int s = j; s > 0; s = (s - 1) & j) {
                    if (requirements[s] <= count.get(items.get(i)) && dp[i][j ^ s]) {
                        dp[i + 1][j] = true;
                        break;
                    }
                }
            }
        }
        return dp[n][(1 << m) - 1];
    }
}