Facebook Pixel

1655. Distribute Repeating Integers

Problem Description

You have an array nums containing n integers, where there are at most 50 unique values in the array. You also have an array quantity containing m customer orders, where quantity[i] represents how many integers the i-th customer wants.

You need to distribute the integers from nums to satisfy all customers with the following conditions:

  1. Each customer i must receive exactly quantity[i] integers
  2. All integers given to a single customer must have the same value (for example, if customer 1 gets 3 integers, they must all be the same number like [5, 5, 5])
  3. Every customer must be satisfied with their allocation

The task is to determine if it's possible to distribute all integers from nums according to these rules. Return true if such a distribution exists, otherwise return false.

For example, if nums = [1, 1, 2, 2, 2] and quantity = [2, 3], you could give customer 0 two 1's and customer 1 three 2's, making it possible to satisfy all customers, so the answer would be true.

Flowchart Walkthrough

First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:

Is it a graph?

  • No: The problem doesn't involve nodes and edges or graph traversal. We're dealing with distributing integers from an array to customers.

Need to solve for kth smallest/largest?

  • No: We're not looking for the kth smallest or largest element. We need to determine if a valid distribution exists.

Involves Linked Lists?

  • No: The problem works with arrays (nums and quantity), not linked lists.

Does the problem have small constraints?

  • Yes: The problem explicitly states there are at most 50 unique values in nums, and looking at the quantity array which represents customers, the constraint is typically small (≤10 customers). The solution uses bit manipulation with 1 << m where m is the length of quantity, indicating we're dealing with small constraint sizes that allow exploring all subsets.

Brute force / Backtracking?

  • Yes: With small constraints, we can explore different ways to assign groups of identical numbers to customers. The solution needs to try different combinations of assigning available counts of each unique number to different subsets of customers, which is a classic backtracking scenario where we explore all possible distributions.

Conclusion: The flowchart correctly leads us to use a Brute force/Backtracking approach. While the actual solution implements this through dynamic programming with state compression (using bitmasks to represent subsets of customers), the core idea is still exploring all possible ways to distribute the available counts of unique numbers to satisfy customer demands - a backtracking pattern optimized through DP.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is recognizing that we only care about the counts of each unique value in nums, not the actual values themselves. If we have five 2's and three 7's, what matters is that we have a group of 5 identical numbers and a group of 3 identical numbers.

Since each customer wants all their integers to be the same value, we can think of this as: "Can we assign the available groups of identical numbers to satisfy all customers?"

With at most 50 unique values and typically around 10 customers (small constraints), we can explore different ways to distribute these groups. But naive backtracking would be inefficient because we'd repeatedly solve the same subproblems.

Here's where the breakthrough comes: We can represent which customers have been satisfied using a bitmask. If we have 3 customers, the bitmask 101 means customers 0 and 2 are satisfied. This allows us to use dynamic programming to remember: "Can we satisfy this specific subset of customers using the first i groups of numbers?"

The state f[i][j] answers: "Can we satisfy the customer subset j using only the first i unique numbers from our array?"

For each state, we try all possible ways to use the current group of identical numbers:

  • We could use it to satisfy customer subset k (if the group is large enough)
  • The remaining customers (j XOR k) should be satisfiable using the previous groups

By trying all possible subsets k of j, we're essentially doing optimized backtracking - exploring all distributions but memorizing results to avoid redundant work.

The preprocessing step s[j] that calculates the total demand for each customer subset helps us quickly check if a group of identical numbers is large enough to satisfy that subset.

Learn more about Dynamic Programming, Backtracking and Bitmask patterns.

Solution Approach

The solution uses state compression dynamic programming combined with subset enumeration to efficiently explore all possible distributions.

Step 1: Count frequencies and prepare data

  • Count occurrences of each number in nums using a Counter: cnt = Counter(nums)
  • Extract just the counts into array arr since actual values don't matter
  • Store n = len(arr) (number of unique values) and m = len(quantity) (number of customers)

Step 2: Precompute subset sums

  • Create array s where s[mask] represents the total quantity demanded by the customer subset represented by mask
  • For each mask from 1 to (1 << m) - 1:
    • Find the first set bit j in the mask
    • Calculate s[mask] = s[mask ^ (1 << j)] + quantity[j]
  • This allows O(1) lookup of total demand for any customer subset

Step 3: Initialize DP table

  • Create 2D DP table f[n][1 << m] where f[i][j] represents whether we can satisfy customer subset j using only the first i+1 unique numbers
  • Initialize f[i][0] = True for all i (empty subset is always satisfiable)

Step 4: Fill DP table For each unique number i with count x = arr[i]:

  • For each customer subset j from 1 to (1 << m) - 1:
    • Option 1: Don't use current number for subset j
      • If i > 0 and f[i-1][j] = True, then f[i][j] = True
    • Option 2: Use current number for some subset k of j
      • Enumerate all subsets k of j using k = (k - 1) & j
      • Check if:
        • Previous numbers can satisfy remaining customers: f[i-1][j ^ k] = True (or j == k if i == 0)
        • Current number has enough count: s[k] <= x
      • If both conditions met, set f[i][j] = True

Step 5: Return result

  • Return f[n-1][(1 << m) - 1], which indicates whether all customers can be satisfied using all available unique numbers

The subset enumeration technique k = (k - 1) & j efficiently iterates through all subsets of j in decreasing order, ensuring we check all possible ways to use the current group of identical numbers.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a small example to illustrate the solution approach.

Example: nums = [1, 1, 2, 2, 2], quantity = [2, 3]

Step 1: Count frequencies and prepare data

  • Count occurrences: {1: 2, 2: 3}
  • Extract counts: arr = [2, 3] (we have 2 ones and 3 twos)
  • n = 2 (two unique values), m = 2 (two customers)

Step 2: Precompute subset sums Calculate total demand for each customer subset:

  • s[00] = 0 (no customers)
  • s[01] = quantity[0] = 2 (customer 0 only)
  • s[10] = quantity[1] = 3 (customer 1 only)
  • s[11] = quantity[0] + quantity[1] = 5 (both customers)

Step 3: Initialize DP table Create f[2][4] table (2 unique numbers × 4 possible customer subsets):

f[0][00] = True  (empty subset always satisfiable)
f[1][00] = True

Step 4: Fill DP table

Processing first unique number (2 ones):

  • f[0][01]: Can we satisfy customer 0 using 2 ones?
    • Check subset 01: Need 2 items, have 2 ones ✓
    • Set f[0][01] = True
  • f[0][10]: Can we satisfy customer 1 using 2 ones?
    • Check subset 10: Need 3 items, have 2 ones ✗
    • Set f[0][10] = False
  • f[0][11]: Can we satisfy both customers using 2 ones?
    • Check subset 01: Need 2 items, have 2 ones ✓, but remaining subset 10 needs 3 items
    • Check subset 10: Need 3 items, have 2 ones ✗
    • Check subset 11: Need 5 items, have 2 ones ✗
    • Set f[0][11] = False

Processing second unique number (3 twos):

  • f[1][01]: Can we satisfy customer 0 using first two groups?
    • Inherit from f[0][01] = True (already satisfied with ones)
    • Set f[1][01] = True
  • f[1][10]: Can we satisfy customer 1 using first two groups?
    • Check if we can use 3 twos for customer 1: Need 3, have 3 ✓
    • Previous groups must satisfy empty set: f[0][00] = True
    • Set f[1][10] = True
  • f[1][11]: Can we satisfy both customers using first two groups?
    • Try using twos for subset 10 (customer 1):
      • Need 3 items, have 3 twos ✓
      • Remaining subset 01 must be satisfied by ones: f[0][01] = True
    • Set f[1][11] = True

Step 5: Return result

  • Check f[1][11] = True, meaning we can satisfy all customers using all available numbers
  • Return true

The solution correctly identifies that we can give customer 0 the two 1's and customer 1 the three 2's, satisfying everyone's requirements.

Solution Implementation

1class Solution:
2    def canDistribute(self, nums: List[int], quantity: List[int]) -> bool:
3        num_customers = len(quantity)
4      
5        # Precompute sum of quantities for each subset of customers
6        # subset_sum[mask] = total quantity needed for customers in mask
7        subset_sum = [0] * (1 << num_customers)
8        for mask in range(1, 1 << num_customers):
9            # Find the first set bit and calculate sum incrementally
10            for customer_idx in range(num_customers):
11                if mask >> customer_idx & 1:
12                    # Remove this customer from mask and add their quantity
13                    subset_sum[mask] = subset_sum[mask ^ (1 << customer_idx)] + quantity[customer_idx]
14                    break
15      
16        # Count frequency of each number in nums
17        frequency_map = Counter(nums)
18        unique_values = list(frequency_map.values())
19        num_unique = len(unique_values)
20      
21        # dp[i][mask] = True if we can satisfy customers in mask using first i+1 unique numbers
22        dp = [[False] * (1 << num_customers) for _ in range(num_unique)]
23      
24        # Base case: empty set of customers can always be satisfied
25        for i in range(num_unique):
26            dp[i][0] = True
27      
28        # Fill the DP table
29        for idx, count in enumerate(unique_values):
30            for customer_mask in range(1, 1 << num_customers):
31                # Case 1: If we could satisfy this mask without current number
32                if idx > 0 and dp[idx - 1][customer_mask]:
33                    dp[idx][customer_mask] = True
34                    continue
35              
36                # Case 2: Try to use current number for some subset of customers
37                subset = customer_mask
38                while subset:
39                    # Check if we can satisfy 'subset' with current number
40                    # and remaining customers with previous numbers
41                    can_use_previous = (customer_mask == subset if idx == 0 
42                                       else dp[idx - 1][customer_mask ^ subset])
43                    can_satisfy_subset = subset_sum[subset] <= count
44                  
45                    if can_use_previous and can_satisfy_subset:
46                        dp[idx][customer_mask] = True
47                        break
48                  
49                    # Move to next subset of customer_mask
50                    subset = (subset - 1) & customer_mask
51      
52        # Return whether we can satisfy all customers using all unique numbers
53        return dp[-1][-1]
54
1class Solution {
2    public boolean canDistribute(int[] nums, int[] quantity) {
3        int numCustomers = quantity.length;
4      
5        // Precompute sum of quantities for each subset of customers
6        // subsetSum[mask] = sum of quantities for customers in the mask
7        int[] subsetSum = new int[1 << numCustomers];
8        for (int mask = 1; mask < (1 << numCustomers); ++mask) {
9            // Find the first set bit and calculate sum based on previous subset
10            for (int bit = 0; bit < numCustomers; ++bit) {
11                if ((mask >> bit & 1) != 0) {
12                    // Remove current bit from mask and add current quantity
13                    subsetSum[mask] = subsetSum[mask ^ (1 << bit)] + quantity[bit];
14                    break;
15                }
16            }
17        }
18      
19        // Count frequency of each number in nums array
20        Map<Integer, Integer> frequencyMap = new HashMap<>(50);
21        for (int num : nums) {
22            frequencyMap.merge(num, 1, Integer::sum);
23        }
24      
25        // Convert frequency map values to array for easier access
26        int numDistinctValues = frequencyMap.size();
27        int[] frequencies = new int[numDistinctValues];
28        int index = 0;
29        for (int frequency : frequencyMap.values()) {
30            frequencies[index++] = frequency;
31        }
32      
33        // dp[i][mask] = whether we can satisfy customers in mask using first i+1 distinct values
34        boolean[][] dp = new boolean[numDistinctValues][1 << numCustomers];
35      
36        // Base case: empty mask can always be satisfied
37        for (int i = 0; i < numDistinctValues; ++i) {
38            dp[i][0] = true;
39        }
40      
41        // Fill DP table
42        for (int i = 0; i < numDistinctValues; ++i) {
43            for (int mask = 1; mask < (1 << numCustomers); ++mask) {
44                // Option 1: Don't use current distinct value for this mask
45                // (inherit result from previous distinct value)
46                if (i > 0 && dp[i - 1][mask]) {
47                    dp[i][mask] = true;
48                    continue;
49                }
50              
51                // Option 2: Use current distinct value for some subset of the mask
52                // Iterate through all non-empty subsets of current mask
53                for (int subset = mask; subset > 0; subset = (subset - 1) & mask) {
54                    // Check if we can satisfy remaining customers with previous values
55                    boolean canSatisfyRemaining = (i == 0) ? (mask == subset) : dp[i - 1][mask ^ subset];
56                  
57                    // Check if current distinct value has enough frequency for this subset
58                    boolean hasEnoughFrequency = subsetSum[subset] <= frequencies[i];
59                  
60                    if (canSatisfyRemaining && hasEnoughFrequency) {
61                        dp[i][mask] = true;
62                        break;
63                    }
64                }
65            }
66        }
67      
68        // Return whether we can satisfy all customers using all distinct values
69        return dp[numDistinctValues - 1][(1 << numCustomers) - 1];
70    }
71}
72
1class Solution {
2public:
3    bool canDistribute(vector<int>& nums, vector<int>& quantity) {
4        int customerCount = quantity.size();
5      
6        // Precompute sum of quantities for each subset of customers
7        // subsetSum[mask] = sum of quantities for customers in the mask
8        int subsetSum[1 << customerCount];
9        memset(subsetSum, 0, sizeof(subsetSum));
10      
11        // Calculate sum for each subset using dynamic programming
12        for (int mask = 1; mask < (1 << customerCount); ++mask) {
13            for (int j = 0; j < customerCount; ++j) {
14                if (mask >> j & 1) {  // If j-th customer is in the subset
15                    // Remove j-th customer from mask and add their quantity
16                    subsetSum[mask] = subsetSum[mask ^ (1 << j)] + quantity[j];
17                    break;
18                }
19            }
20        }
21      
22        // Count frequency of each value in nums
23        unordered_map<int, int> frequencyMap;
24        for (int& value : nums) {
25            ++frequencyMap[value];
26        }
27      
28        // Convert frequency map to array for easier indexing
29        int uniqueValueCount = frequencyMap.size();
30        vector<int> frequencies;
31        for (auto& [value, freq] : frequencyMap) {
32            frequencies.push_back(freq);
33        }
34      
35        // dp[i][mask] = true if we can satisfy customers in mask using first i+1 unique values
36        bool dp[uniqueValueCount][1 << customerCount];
37        memset(dp, 0, sizeof(dp));
38      
39        // Base case: empty subset can always be satisfied
40        for (int i = 0; i < uniqueValueCount; ++i) {
41            dp[i][0] = true;
42        }
43      
44        // Fill the DP table
45        for (int i = 0; i < uniqueValueCount; ++i) {
46            for (int mask = 1; mask < (1 << customerCount); ++mask) {
47                // Case 1: Inherit from previous unique value (don't use current value)
48                if (i > 0 && dp[i - 1][mask]) {
49                    dp[i][mask] = true;
50                    continue;
51                }
52              
53                // Case 2: Try to use current unique value for some subset
54                // Iterate through all subsets of the current mask
55                for (int subset = mask; subset > 0; subset = (subset - 1) & mask) {
56                    // Check if we can satisfy remaining customers with previous values
57                    bool canSatisfyRemaining = (i == 0) ? (mask == subset) : dp[i - 1][mask ^ subset];
58                  
59                    // Check if current value has enough frequency for this subset
60                    bool hasEnoughFrequency = subsetSum[subset] <= frequencies[i];
61                  
62                    if (canSatisfyRemaining && hasEnoughFrequency) {
63                        dp[i][mask] = true;
64                        break;
65                    }
66                }
67            }
68        }
69      
70        // Check if we can satisfy all customers using all unique values
71        return dp[uniqueValueCount - 1][(1 << customerCount) - 1];
72    }
73};
74
1/**
2 * Determines if we can distribute nums to satisfy all quantity requirements
3 * @param nums - Array of numbers to distribute
4 * @param quantity - Array of required quantities for each customer
5 * @returns true if distribution is possible, false otherwise
6 */
7function canDistribute(nums: number[], quantity: number[]): boolean {
8    const numCustomers: number = quantity.length;
9  
10    // Precompute sum of quantities for each subset of customers
11    // subsetSums[mask] = total quantity needed for customers in subset represented by mask
12    const subsetSums: number[] = new Array(1 << numCustomers).fill(0);
13    for (let mask = 1; mask < (1 << numCustomers); ++mask) {
14        // Find the first set bit and calculate sum based on previous subset
15        for (let customerIdx = 0; customerIdx < numCustomers; ++customerIdx) {
16            if ((mask >> customerIdx) & 1) {
17                // Remove current customer from mask and add their quantity
18                subsetSums[mask] = subsetSums[mask ^ (1 << customerIdx)] + quantity[customerIdx];
19                break;
20            }
21        }
22    }
23  
24    // Count frequency of each unique number in nums
25    const frequencyMap: Map<number, number> = new Map();
26    for (const num of nums) {
27        frequencyMap.set(num, (frequencyMap.get(num) || 0) + 1);
28    }
29  
30    // Extract frequencies into an array for easier indexing
31    const numUniqueValues: number = frequencyMap.size;
32    const frequencies: number[] = [];
33    for (const [_, frequency] of frequencyMap) {
34        frequencies.push(frequency);
35    }
36  
37    // DP table: canSatisfy[i][mask] = true if we can satisfy customers in mask
38    // using only the first i+1 unique values
39    const canSatisfy: boolean[][] = new Array(numUniqueValues)
40        .fill(false)
41        .map(() => new Array(1 << numCustomers).fill(false));
42  
43    // Base case: empty set of customers can always be satisfied
44    for (let valueIdx = 0; valueIdx < numUniqueValues; ++valueIdx) {
45        canSatisfy[valueIdx][0] = true;
46    }
47  
48    // Fill DP table
49    for (let valueIdx = 0; valueIdx < numUniqueValues; ++valueIdx) {
50        for (let customerMask = 0; customerMask < (1 << numCustomers); ++customerMask) {
51            // Option 1: Don't use current value, inherit from previous values
52            if (valueIdx > 0 && canSatisfy[valueIdx - 1][customerMask]) {
53                canSatisfy[valueIdx][customerMask] = true;
54                continue;
55            }
56          
57            // Option 2: Use current value to satisfy some subset of remaining customers
58            // Iterate through all subsets of customerMask
59            for (let subset = customerMask; subset > 0; subset = (subset - 1) & customerMask) {
60                // Check if we can satisfy the remaining customers with previous values
61                const canSatisfyRemaining: boolean = 
62                    (valueIdx === 0 && customerMask === subset) || 
63                    (valueIdx > 0 && canSatisfy[valueIdx - 1][customerMask ^ subset]);
64              
65                // Check if current value has enough frequency for this subset
66                const hasEnoughFrequency: boolean = subsetSums[subset] <= frequencies[valueIdx];
67              
68                if (canSatisfyRemaining && hasEnoughFrequency) {
69                    canSatisfy[valueIdx][customerMask] = true;
70                    break;
71                }
72            }
73        }
74    }
75  
76    // Check if we can satisfy all customers using all unique values
77    return canSatisfy[numUniqueValues - 1][(1 << numCustomers) - 1];
78}
79

Time and Space Complexity

Time Complexity: O(n * 3^m)

The time complexity analysis breaks down as follows:

  • Computing the sum array s takes O(2^m * m) time, where we iterate through all 2^m subsets and for each subset, we may iterate through m positions to find the first set bit.
  • The main dynamic programming section has:
    • Outer loop iterating through n different values (unique counts in nums)
    • Middle loop iterating through all 2^m possible subsets j
    • Inner while loop that iterates through all subsets k of j

For the inner loop, the key insight is that for a fixed j, the number of subsets k of j is 2^(number of 1s in j). Summing over all possible j values:

  • Each element in quantity can be in one of 3 states relative to subsets j and k: not in j, in j but not in k, or in both j and k
  • This gives us 3^m total iterations when summing across all j and their subsets k

Therefore, the overall time complexity is O(2^m * m + n * 3^m) = O(n * 3^m) since 3^m dominates 2^m * m.

Space Complexity: O(n * 2^m)

The space complexity comes from:

  • Array s storing sums for all 2^m subsets: O(2^m)
  • 2D DP array f with dimensions n × 2^m: O(n * 2^m)
  • Counter and array storage: O(n)

The dominant term is O(n * 2^m) from the DP table.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Inefficient Subset Enumeration Leading to TLE

A common mistake is using inefficient methods to enumerate subsets, such as generating all possible subsets and checking if each is a subset of the target mask. This approach has exponential time complexity that becomes prohibitive even for moderate input sizes.

Incorrect approach:

# Inefficient: Checking all 2^m subsets for each mask
for subset in range(1 << num_customers):
    if (subset & customer_mask) == subset:  # Check if subset of customer_mask
        # Process subset

Correct approach:

# Efficient: Only enumerate actual subsets of customer_mask
subset = customer_mask
while subset:
    # Process subset
    subset = (subset - 1) & customer_mask

The key insight is that (subset - 1) & customer_mask generates the next smaller subset directly, visiting only actual subsets rather than all possible combinations.

2. Incorrect DP State Initialization

Another pitfall is forgetting to properly handle the base case when idx == 0. When processing the first unique number, there are no "previous numbers" to rely on, so the condition for using this number differs from subsequent iterations.

Incorrect initialization:

# Wrong: Always checking dp[idx-1] even when idx == 0
if dp[idx - 1][customer_mask ^ subset] and subset_sum[subset] <= count:
    dp[idx][customer_mask] = True

Correct initialization:

# Correct: Special handling for first unique number
can_use_previous = (customer_mask == subset if idx == 0 
                   else dp[idx - 1][customer_mask ^ subset])
if can_use_previous and subset_sum[subset] <= count:
    dp[idx][customer_mask] = True

When idx == 0, we can only satisfy customer_mask if we use all of it with the current number (hence customer_mask == subset), since there are no previous numbers available.

3. Memory Optimization Oversight

While not necessarily incorrect, failing to optimize memory usage can be problematic for larger inputs. Since each DP state only depends on the previous row, we can use rolling arrays to reduce space complexity from O(n × 2^m) to O(2^m).

Memory-optimized version:

# Use two 1D arrays instead of 2D array
prev = [False] * (1 << num_customers)
curr = [False] * (1 << num_customers)
prev[0] = True

for count in unique_values:
    curr[0] = True
    for customer_mask in range(1, 1 << num_customers):
        curr[customer_mask] = prev[customer_mask]  # Don't use current number
      
        subset = customer_mask
        while subset and not curr[customer_mask]:
            if prev[customer_mask ^ subset] and subset_sum[subset] <= count:
                curr[customer_mask] = True
            subset = (subset - 1) & customer_mask
  
    prev, curr = curr, prev

return prev[-1]
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which technique can we use to find the middle of a linked list?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More