|
1 | 1 | package com.thealgorithms.others; |
2 | 2 |
|
3 | | -import java.util.HashSet; |
4 | | -import java.util.Set; |
| 3 | +import java.util.HashMap; |
| 4 | +import java.util.Map; |
5 | 5 |
|
6 | 6 | /** |
7 | | - * References: https://en.wikipedia.org/wiki/Streaming_algorithm |
| 7 | + * Algorithm to find the maximum sum of a subarray of size K with all distinct |
| 8 | + * elements. |
8 | 9 | * |
9 | | - * This model involves computing the maximum sum of subarrays of a fixed size \( K \) from a stream of integers. |
10 | | - * As the stream progresses, elements from the end of the window are removed, and new elements from the stream are added. |
| 10 | + * This implementation uses a sliding window approach with a hash map to |
| 11 | + * efficiently |
| 12 | + * track element frequencies within the current window. The algorithm maintains |
| 13 | + * a window |
| 14 | + * of size K and slides it across the array, ensuring all elements in the window |
| 15 | + * are distinct. |
11 | 16 | * |
| 17 | + * Time Complexity: O(n) where n is the length of the input array |
| 18 | + * Space Complexity: O(k) for storing elements in the hash map |
| 19 | + * |
| 20 | + * @see <a href="https://en.wikipedia.org/wiki/Streaming_algorithm">Streaming |
| 21 | + * Algorithm</a> |
| 22 | + * @see <a href="https://en.wikipedia.org/wiki/Sliding_window_protocol">Sliding |
| 23 | + * Window</a> |
12 | 24 | * @author Swarga-codes (https://github.com/Swarga-codes) |
13 | 25 | */ |
14 | 26 | public final class MaximumSumOfDistinctSubarraysWithLengthK { |
15 | 27 | private MaximumSumOfDistinctSubarraysWithLengthK() { |
16 | 28 | } |
17 | 29 |
|
18 | 30 | /** |
19 | | - * Finds the maximum sum of a subarray of size K consisting of distinct elements. |
| 31 | + * Finds the maximum sum of a subarray of size K consisting of distinct |
| 32 | + * elements. |
20 | 33 | * |
21 | | - * @param k The size of the subarray. |
22 | | - * @param nums The array from which subarrays will be considered. |
| 34 | + * The algorithm uses a sliding window technique with a frequency map to track |
| 35 | + * the count of each element in the current window. A window is valid only if |
| 36 | + * all K elements are distinct (frequency map size equals K). |
23 | 37 | * |
24 | | - * @return The maximum sum of any distinct-element subarray of size K. If no such subarray exists, returns 0. |
| 38 | + * @param k The size of the subarray. Must be non-negative. |
| 39 | + * @param nums The array from which subarrays will be considered. |
| 40 | + * @return The maximum sum of any distinct-element subarray of size K. |
| 41 | + * Returns 0 if no such subarray exists or if k is 0 or negative. |
| 42 | + * @throws IllegalArgumentException if k is negative |
25 | 43 | */ |
26 | 44 | public static long maximumSubarraySum(int k, int... nums) { |
27 | | - if (nums.length < k) { |
| 45 | + if (k <= 0 || nums == null || nums.length < k) { |
28 | 46 | return 0; |
29 | 47 | } |
30 | | - long masSum = 0; // Variable to store the maximum sum of distinct subarrays |
31 | | - long currentSum = 0; // Variable to store the sum of the current subarray |
32 | | - Set<Integer> currentSet = new HashSet<>(); // Set to track distinct elements in the current subarray |
33 | 48 |
|
34 | | - // Initialize the first window |
| 49 | + long maxSum = 0; |
| 50 | + long currentSum = 0; |
| 51 | + Map<Integer, Integer> frequencyMap = new HashMap<>(); |
| 52 | + |
| 53 | + // Initialize the first window of size k |
35 | 54 | for (int i = 0; i < k; i++) { |
36 | 55 | currentSum += nums[i]; |
37 | | - currentSet.add(nums[i]); |
| 56 | + frequencyMap.put(nums[i], frequencyMap.getOrDefault(nums[i], 0) + 1); |
38 | 57 | } |
39 | | - // If the first window contains distinct elements, update maxSum |
40 | | - if (currentSet.size() == k) { |
41 | | - masSum = currentSum; |
| 58 | + |
| 59 | + // Check if the first window has all distinct elements |
| 60 | + if (frequencyMap.size() == k) { |
| 61 | + maxSum = currentSum; |
42 | 62 | } |
| 63 | + |
43 | 64 | // Slide the window across the array |
44 | | - for (int i = 1; i < nums.length - k + 1; i++) { |
45 | | - // Update the sum by removing the element that is sliding out and adding the new element |
46 | | - currentSum = currentSum - nums[i - 1]; |
47 | | - currentSum = currentSum + nums[i + k - 1]; |
48 | | - int j = i; |
49 | | - boolean flag = false; // flag value which says that the subarray contains distinct elements |
50 | | - while (j < i + k && currentSet.size() < k) { |
51 | | - if (nums[i - 1] == nums[j]) { |
52 | | - flag = true; |
53 | | - break; |
54 | | - } else { |
55 | | - j++; |
56 | | - } |
57 | | - } |
58 | | - if (!flag) { |
59 | | - currentSet.remove(nums[i - 1]); |
| 65 | + for (int i = k; i < nums.length; i++) { |
| 66 | + // Remove the leftmost element from the window |
| 67 | + int leftElement = nums[i - k]; |
| 68 | + currentSum -= leftElement; |
| 69 | + int leftFrequency = frequencyMap.get(leftElement); |
| 70 | + if (leftFrequency == 1) { |
| 71 | + frequencyMap.remove(leftElement); |
| 72 | + } else { |
| 73 | + frequencyMap.put(leftElement, leftFrequency - 1); |
60 | 74 | } |
61 | | - currentSet.add(nums[i + k - 1]); |
62 | | - // If the current window has distinct elements, compare and possibly update maxSum |
63 | | - if (currentSet.size() == k && masSum < currentSum) { |
64 | | - masSum = currentSum; |
| 75 | + |
| 76 | + // Add the new rightmost element to the window |
| 77 | + int rightElement = nums[i]; |
| 78 | + currentSum += rightElement; |
| 79 | + frequencyMap.put(rightElement, frequencyMap.getOrDefault(rightElement, 0) + 1); |
| 80 | + |
| 81 | + // If all elements in the window are distinct, update maxSum if needed |
| 82 | + if (frequencyMap.size() == k && currentSum > maxSum) { |
| 83 | + maxSum = currentSum; |
65 | 84 | } |
66 | 85 | } |
67 | | - return masSum; // the final maximum sum |
| 86 | + |
| 87 | + return maxSum; |
68 | 88 | } |
69 | 89 | } |
0 commit comments