Facebook Pixel

2461. Maximum Sum of Distinct Subarrays With Length K

Problem Description

You have an integer array nums and an integer k. Your task is to find the maximum sum among all subarrays that satisfy two specific conditions:

  1. The subarray must have exactly k elements
  2. All elements in the subarray must be distinct (no duplicates)

A subarray is a contiguous sequence of elements from the original array. For example, if nums = [1, 2, 3], then [1, 2] and [2, 3] are subarrays, but [1, 3] is not.

You need to examine all possible subarrays of length k and check if they contain only unique elements. Among all valid subarrays (those with distinct elements), return the one with the maximum sum. If no subarray of length k has all distinct elements, return 0.

For example:

  • If nums = [1, 5, 4, 2, 9, 9, 9] and k = 3, the subarrays of length 3 are: [1, 5, 4], [5, 4, 2], [4, 2, 9], [2, 9, 9], and [9, 9, 9]. Only [1, 5, 4], [5, 4, 2], and [4, 2, 9] have all distinct elements. Their sums are 10, 11, and 15 respectively, so the answer is 15.

  • If nums = [4, 4, 4] and k = 3, the only subarray [4, 4, 4] contains duplicate elements, so the answer is 0.

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

Intuition

The key insight is that we need to check every possible subarray of length k to find the one with maximum sum that has all distinct elements. Since we're looking at consecutive subarrays of fixed length, this naturally suggests using a sliding window approach.

Think of it like a window of size k that slides over the array from left to right. Initially, the window covers elements from index 0 to k-1. Then we slide it one position to the right, removing the leftmost element and adding a new element from the right.

To efficiently check if all elements in the current window are distinct, we need to track the frequency of each element. A hash table (or Counter in Python) is perfect for this - we can maintain counts of all elements currently in the window. When all elements are distinct, each element appears exactly once, so the size of our hash table equals k.

As we slide the window:

  1. Add the new element entering the window (increment its count)
  2. Remove the element leaving the window (decrement its count)
  3. If an element's count drops to 0, remove it from the hash table entirely
  4. Update the window sum by adding the new element and subtracting the removed element

The beauty of this approach is that we don't need to recalculate the sum from scratch for each window - we can update it incrementally by just adjusting for the element that entered and the element that left. Similarly, we don't need to rebuild the frequency map each time; we just update it for the two elements that changed.

Whenever the hash table size equals k (meaning all elements are distinct), we check if the current sum is larger than our maximum found so far.

Learn more about Sliding Window patterns.

Solution Approach

We implement a sliding window technique combined with a hash table to efficiently track distinct elements and their counts.

Initial Setup:

  1. Create a Counter cnt to store the frequency of elements in the first window (elements from index 0 to k-1)
  2. Calculate the initial sum s of the first k elements
  3. Initialize the answer ans - if the first window has all distinct elements (checked by len(cnt) == k), set ans = s, otherwise ans = 0

Sliding the Window: Starting from index k, we iterate through the rest of the array. For each step:

  1. Add the new element:

    • cnt[nums[i]] += 1 - increment the count of the element entering the window
    • s += nums[i] - add it to the running sum
  2. Remove the old element:

    • cnt[nums[i - k]] -= 1 - decrement the count of the element leaving the window
    • If the count becomes 0, remove it from the hash table: cnt.pop(nums[i - k])
    • s -= nums[i - k] - subtract it from the running sum
  3. Check validity and update answer:

    • If len(cnt) == k, all elements in the current window are distinct
    • Update ans = max(ans, s) if the current sum is larger

Why this works:

  • The Counter maintains exact frequencies of elements in the current window
  • When len(cnt) == k, it means we have exactly k different elements, each appearing once
  • The running sum s is maintained incrementally by adding the new element and subtracting the old one, avoiding recalculation
  • Time complexity is O(n) where n is the length of the array, as we visit each element once
  • Space complexity is O(k) for storing at most k elements in the Counter

The algorithm efficiently finds the maximum sum among all valid subarrays without having to recompute everything for each window position.

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 the solution with nums = [1, 5, 4, 2, 9, 9, 9] and k = 3.

Initial Setup (First Window: [1, 5, 4])

  • Create Counter: cnt = {1: 1, 5: 1, 4: 1}
  • Calculate initial sum: s = 1 + 5 + 4 = 10
  • Check if valid: len(cnt) = 3 = k ✓ (all elements distinct)
  • Initialize answer: ans = 10

Slide 1: Move to [5, 4, 2] (i = 3)

  • Add new element nums[3] = 2:
    • cnt[2] += 1cnt = {1: 1, 5: 1, 4: 1, 2: 1}
    • s = 10 + 2 = 12
  • Remove old element nums[0] = 1:
    • cnt[1] -= 1 → count becomes 0, so remove from cnt
    • cnt = {5: 1, 4: 1, 2: 1}
    • s = 12 - 1 = 11
  • Check validity: len(cnt) = 3 = k
  • Update answer: ans = max(10, 11) = 11

Slide 2: Move to [4, 2, 9] (i = 4)

  • Add new element nums[4] = 9:
    • cnt[9] += 1cnt = {5: 1, 4: 1, 2: 1, 9: 1}
    • s = 11 + 9 = 20
  • Remove old element nums[1] = 5:
    • cnt[5] -= 1 → count becomes 0, so remove from cnt
    • cnt = {4: 1, 2: 1, 9: 1}
    • s = 20 - 5 = 15
  • Check validity: len(cnt) = 3 = k
  • Update answer: ans = max(11, 15) = 15

Slide 3: Move to [2, 9, 9] (i = 5)

  • Add new element nums[5] = 9:
    • cnt[9] += 1cnt = {4: 1, 2: 1, 9: 2}
    • s = 15 + 9 = 24
  • Remove old element nums[2] = 4:
    • cnt[4] -= 1 → count becomes 0, so remove from cnt
    • cnt = {2: 1, 9: 2}
    • s = 24 - 4 = 20
  • Check validity: len(cnt) = 2 ≠ k ✗ (has duplicates)
  • Answer remains: ans = 15

Slide 4: Move to [9, 9, 9] (i = 6)

  • Add new element nums[6] = 9:
    • cnt[9] += 1cnt = {2: 1, 9: 3}
    • s = 20 + 9 = 29
  • Remove old element nums[3] = 2:
    • cnt[2] -= 1 → count becomes 0, so remove from cnt
    • cnt = {9: 3}
    • s = 29 - 2 = 27
  • Check validity: len(cnt) = 1 ≠ k ✗ (has duplicates)
  • Answer remains: ans = 15

Final Result: 15 (from the subarray [4, 2, 9])

Solution Implementation

1class Solution:
2    def maximumSubarraySum(self, nums: List[int], k: int) -> int:
3        # Initialize a counter to track element frequencies in the current window
4        element_count = Counter(nums[:k])
5      
6        # Calculate the sum of the first k elements
7        current_sum = sum(nums[:k])
8      
9        # Initialize the answer: if first window has all distinct elements, use its sum, otherwise 0
10        max_sum = current_sum if len(element_count) == k else 0
11      
12        # Slide the window through the rest of the array
13        for i in range(k, len(nums)):
14            # Add the new element to the window
15            element_count[nums[i]] += 1
16          
17            # Remove the leftmost element from the window
18            element_count[nums[i - k]] -= 1
19          
20            # If count becomes 0, remove the element from the counter entirely
21            if element_count[nums[i - k]] == 0:
22                element_count.pop(nums[i - k])
23          
24            # Update the current window sum
25            current_sum += nums[i] - nums[i - k]
26          
27            # If all elements in the window are distinct, update the maximum sum
28            if len(element_count) == k:
29                max_sum = max(max_sum, current_sum)
30      
31        return max_sum
32
1class Solution {
2    public long maximumSubarraySum(int[] nums, int k) {
3        int n = nums.length;
4      
5        // HashMap to track frequency of elements in current window
6        Map<Integer, Integer> frequencyMap = new HashMap<>(k);
7      
8        // Initialize the first window of size k
9        long currentSum = 0;
10        for (int i = 0; i < k; i++) {
11            frequencyMap.merge(nums[i], 1, Integer::sum);
12            currentSum += nums[i];
13        }
14      
15        // If all k elements are distinct, set initial answer to current sum, otherwise 0
16        long maxSum = (frequencyMap.size() == k) ? currentSum : 0;
17      
18        // Slide the window through the rest of the array
19        for (int i = k; i < n; i++) {
20            // Add the new element to the window
21            frequencyMap.merge(nums[i], 1, Integer::sum);
22          
23            // Remove the leftmost element from the window
24            int leftElement = nums[i - k];
25            if (frequencyMap.merge(leftElement, -1, Integer::sum) == 0) {
26                frequencyMap.remove(leftElement);
27            }
28          
29            // Update the current window sum
30            currentSum = currentSum + nums[i] - nums[i - k];
31          
32            // If all elements in window are distinct, update max sum
33            if (frequencyMap.size() == k) {
34                maxSum = Math.max(maxSum, currentSum);
35            }
36        }
37      
38        return maxSum;
39    }
40}
41
1class Solution {
2public:
3    long long maximumSubarraySum(vector<int>& nums, int k) {
4        using ll = long long;
5        int n = nums.size();
6      
7        // Hash map to track frequency of elements in current window
8        unordered_map<int, ll> frequencyMap;
9      
10        // Current window sum
11        ll windowSum = 0;
12      
13        // Initialize the first window of size k
14        for (int i = 0; i < k; ++i) {
15            frequencyMap[nums[i]]++;
16            windowSum += nums[i];
17        }
18      
19        // Initialize answer: if first window has all distinct elements, use its sum
20        ll maxSum = (frequencyMap.size() == k) ? windowSum : 0;
21      
22        // Slide the window through the rest of the array
23        for (int i = k; i < n; ++i) {
24            // Add new element to the window
25            frequencyMap[nums[i]]++;
26          
27            // Remove the leftmost element from the window
28            int elementToRemove = nums[i - k];
29            frequencyMap[elementToRemove]--;
30            if (frequencyMap[elementToRemove] == 0) {
31                frequencyMap.erase(elementToRemove);
32            }
33          
34            // Update window sum
35            windowSum = windowSum + nums[i] - nums[i - k];
36          
37            // If window has exactly k distinct elements, update maximum sum
38            if (frequencyMap.size() == k) {
39                maxSum = max(maxSum, windowSum);
40            }
41        }
42      
43        return maxSum;
44    }
45};
46
1/**
2 * Finds the maximum sum of a subarray of length k with all distinct elements
3 * @param nums - The input array of numbers
4 * @param k - The length of the subarray
5 * @returns The maximum sum of a subarray of length k with all distinct elements, or 0 if no such subarray exists
6 */
7function maximumSubarraySum(nums: number[], k: number): number {
8    const arrayLength = nums.length;
9    // Map to track frequency of elements in current window
10    const frequencyMap: Map<number, number> = new Map();
11    let currentWindowSum = 0;
12  
13    // Initialize first window of size k
14    for (let i = 0; i < k; ++i) {
15        frequencyMap.set(nums[i], (frequencyMap.get(nums[i]) ?? 0) + 1);
16        currentWindowSum += nums[i];
17    }
18  
19    // Check if first window has all distinct elements (map size equals k)
20    let maxSum = frequencyMap.size === k ? currentWindowSum : 0;
21  
22    // Slide the window through the rest of the array
23    for (let i = k; i < arrayLength; ++i) {
24        // Add new element to the window
25        frequencyMap.set(nums[i], (frequencyMap.get(nums[i]) ?? 0) + 1);
26      
27        // Remove the leftmost element from the window
28        const leftElement = nums[i - k];
29        frequencyMap.set(leftElement, frequencyMap.get(leftElement)! - 1);
30      
31        // If frequency becomes 0, remove the element from map
32        if (frequencyMap.get(leftElement) === 0) {
33            frequencyMap.delete(leftElement);
34        }
35      
36        // Update current window sum
37        currentWindowSum += nums[i] - nums[i - k];
38      
39        // If all elements in window are distinct, update maximum sum
40        if (frequencyMap.size === k) {
41            maxSum = Math.max(maxSum, currentWindowSum);
42        }
43    }
44  
45    return maxSum;
46}
47

Time and Space Complexity

Time Complexity: O(n), where n is the length of the array nums.

The algorithm uses a sliding window approach with a fixed window size k. Initially, it processes the first k elements to build the counter and calculate the initial sum, which takes O(k) time. Then it iterates through the remaining n - k elements once. In each iteration, it performs constant-time operations:

  • Adding and updating a counter entry: O(1) average case for dictionary operations
  • Removing a counter entry if needed: O(1) average case
  • Updating the running sum: O(1)
  • Checking the counter size and updating the maximum: O(1)

Since k ≤ n, the total time complexity is O(k) + O(n - k) = O(n).

Space Complexity: O(k), which can be considered O(n) in the worst case when k = n.

The space is primarily used by the Counter object cnt, which stores at most k distinct elements at any given time (since we're maintaining a sliding window of size k). In the worst case where all elements in the window are distinct, the counter will have exactly k entries. Since k can be at most n, the space complexity is O(min(k, n)), which simplifies to O(n) in the worst case.

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

Common Pitfalls

1. Forgetting to Handle the Initial Window Properly

A common mistake is not checking if the first window (indices 0 to k-1) contains all distinct elements before starting the sliding process. This can lead to missing a valid maximum sum if it occurs in the first window.

Incorrect approach:

max_sum = 0  # Always starting with 0, ignoring the first window
for i in range(k, len(nums)):
    # sliding window logic...

Correct approach:

# Check the first window explicitly
max_sum = current_sum if len(element_count) == k else 0

2. Incorrectly Managing the Counter When Removing Elements

When an element leaves the window, simply decrementing its count isn't enough. If the count reaches zero, the element must be completely removed from the counter. Otherwise, len(element_count) will give an incorrect count of distinct elements.

Incorrect approach:

element_count[nums[i - k]] -= 1
# Forgetting to remove the key when count becomes 0

Correct approach:

element_count[nums[i - k]] -= 1
if element_count[nums[i - k]] == 0:
    element_count.pop(nums[i - k])

3. Using a Set Instead of a Counter

Some might think to use a set to track distinct elements, but this fails when the same element appears multiple times in the window.

Incorrect approach:

window_set = set(nums[:k])
# This loses frequency information

Why it fails: If nums = [1, 2, 3, 1, 5] and k = 3, the window [3, 1, 5] would appear to have 3 distinct elements in a set, but we wouldn't know that when we slide to include the second 1, we now have a duplicate.

4. Off-by-One Errors in Window Boundaries

Ensuring the window contains exactly k elements and correctly identifying which element to add and remove can be tricky.

Common mistake:

# Wrong indices for removal
element_count[nums[i - k + 1]] -= 1  # Should be nums[i - k]

Correct indexing:

  • When at index i, the window spans from i - k + 1 to i
  • The element to remove is at index i - k
  • The element to add is at index i
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of these pictures shows the visit order of a depth-first search?


Recommended Readings

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

Load More