Given an integer array nums and an integer k, return true if nums has a good subarray or false otherwise.
A good subarray is a subarray where:
- its length is at least two, and
- the sum of the elements of the subarray is a multiple of
k.
Note that:
- A subarray is a contiguous part of the array.
- An integer
xis a multiple ofkif there exists an integernsuch thatx = n * k.0is always a multiple ofk.
Example 1:
Input: nums = [23,2,4,6,7], k = 6 Output: true Explanation: [2, 4] is a continuous subarray of size 2 whose elements sum up to 6.
public boolean checkSubarraySum(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>(){{put(0,-1);}};;
int runningSum = 0;
for (int i=0;i<nums.length;i++) {
runningSum += nums[i];
if (k != 0) runningSum %= k;
Integer prev = map.get(runningSum);
if (prev != null) {
if (i - prev > 1) return true;
}
else map.put(runningSum, i);
}
return false;
}
let’s break down this code visually. The goal is to find if there’s a subarray (a continuous part of the array) whose elements sum up to a multiple of k.
The core idea relies on this mathematical property:
If the sum of elements from index 0 to i (let’s call it sum_i) and the sum of elements from index 0 to j (let’s call it sum_j), where j > i, have the same remainder when divided by k, then the sum of the subarray from i+1 to j must be a multiple of k.
Why? If sum_i % k == R and sum_j % k == R, Then (sum_j - sum_i) % k == (R - R) % k == 0. And sum_j - sum_i is exactly the sum of the elements in the subarray (i, j].
The code uses a HashMap to store the first time it sees a particular runningSum % k value.
Visual Explanation
Let’s trace the example: nums = [23, 2, 4, 6, 7] and k = 6.
Initial State:
map = {0: -1}(We initialize with0pointing to-1. This handles cases where the subarray starting from index 0 is a multiple ofk.)runningSum = 0
Iteration 1: i = 0, nums[0] = 23
runningSum += nums[0]=>runningSum = 0 + 23 = 23if (k != 0) runningSum %= k=>runningSum = 23 % 6 = 5[23, 2, 4, 6, 7] ^ runningSum = 23 runningSum % 6 = 5Integer prev = map.get(runningSum)=>prev = map.get(5)which isnull(5 is not in the map yet).else map.put(runningSum, i)=>map.put(5, 0)map = {0: -1, 5: 0}
Iteration 2: i = 1, nums[1] = 2
runningSum += nums[1]=>runningSum = 5 + 2 = 7(RememberrunningSumfrom the previous step was5after the modulo. The code actually adds to the fullrunningSumbefore the modulo, so it should be23 + 2 = 25. Let’s correct that understanding for therunningSumvariable itself. The key for the map is the modulo.) CorrectedrunningSumaccumulation:runningSum = 23(from previous full sum)runningSum += nums[1]=>runningSum = 23 + 2 = 25if (k != 0) runningSum %= k=>currentModulo = 25 % 6 = 1[23, 2, 4, 6, 7] ^ runningSum = 25 (23+2) currentModulo = 25 % 6 = 1Integer prev = map.get(currentModulo)=>prev = map.get(1)which isnull.else map.put(currentModulo, i)=>map.put(1, 1)map = {0: -1, 5: 0, 1: 1}
Iteration 3: i = 2, nums[2] = 4
runningSum += nums[2]=>runningSum = 25 + 4 = 29if (k != 0) runningSum %= k=>currentModulo = 29 % 6 = 5[23, 2, 4, 6, 7] ^ runningSum = 29 (25+4) currentModulo = 29 % 6 = 5Integer prev = map.get(currentModulo)=>prev = map.get(5)which is0.if (prev != null)is true.if (i - prev > 1)=>if (2 - 0 > 1)=>if (2 > 1)which is true.return true;

The diagram provides a flow. I think combining this with the table and the step-by
Visualizing the Process
Let’s use nums = [23, 2, 4, 6, 7] and k = 6.
Key Variables:
runningSum: The sum of elements fromnums[0]up to the current element.map: A dictionary (HashMap) that stores{remainder: index}. It’s initialized with{0: -1}. This special entry helps if a subarray starting from the very beginning (index 0) sums to a multiple ofk. The-1ensures that if the sumnums[0]...nums[i]is a multiple ofk, the lengthi - (-1) = i + 1is considered.i: The current index in thenumsarray.
Step-by-Step:
Initial State:
runningSum = 0map = {0: -1}
Array: [23, 2, 4, 6, 7]
^
i=0
1. i = 0, nums[0] = 23
runningSum = 0 + 23 = 23remainder = runningSum % k = 23 % 6 = 5- Is
remainder (5)inmap? No. - Add
remainder: itomap:map.put(5, 0) mapis now{0: -1, 5: 0}
Visual: Sums: [23] Rem (k=6): [5] Map: {0:-1, 5:0}
Array: [23, 2, 4, 6, 7]
^
i=1
2. i = 1, nums[1] = 2
runningSum = 23 + 2 = 25(This is the actual sum; the variablerunningSumin the code storesrunningSum % kif k is not 0, but it’s easier to think about the true sum first, then the modulo)- The code does
runningSum += nums[i], so ifrunningSumwas5(from23%6), it would become5+2=7. Then7%6 = 1. - Let’s follow the code:
runningSum(from previous step, after modulo) = 5. (If k=0, this step is skipped)runningSum(before addingnums[i]) is actually the full sum up toi-1. So, the code’srunningSumvariable will accumulate the actual sum.runningSum = 23(full sum up to previous element)runningSum += nums[1]=>runningSum = 23 + 2 = 25
remainder = runningSum % k = 25 % 6 = 1- Is
remainder (1)inmap? No. - Add
remainder: itomap:map.put(1, 1) mapis now{0: -1, 5: 0, 1: 1}
Visual: Sums: [23, 25] (sum up to index 0, sum up to index 1) Rem (k=6): [5, 1] Map: {0:-1, 5:0, 1:1}
Array: [23, 2, 4, 6, 7]
^
i=2
3. i = 2, nums[2] = 4
runningSum = 25 + 4 = 29remainder = runningSum % k = 29 % 6 = 5- Is
remainder (5)inmap? Yes!map.get(5)givesprev = 0. - Now, check the condition:
if (i - prev > 1)i = 2,prev = 02 - 0 > 1=>2 > 1. This is TRUE.
- Return
true. We found a subarray!
Visual: Sums: [23, 25, 29] Rem (k=6): [ 5, 1, 5] <– We found a repeated remainder! Map: {0:-1, 5:0, 1:1}
Why did this work?
- At
i = 2, therunningSum % 6is5. (Sum23+2+4 = 29) - We previously saw
runningSum % 6 = 5atprev = 0. (Sum23)
This means the sum of elements between index prev (exclusive) and i (inclusive) is a multiple of k. Subarray: nums[prev + 1 ... i] => nums[0 + 1 ... 2] => nums[1 ... 2] Elements: [2, 4] Sum: 2 + 4 = 6 And 6 is a multiple of k=6. The length of this subarray is i - prev = 2 - 0 = 2. Since 2 > 1, the condition is met.
Diagrammatic Representation of the “Aha!” Moment:
nums: [23, 2, 4, 6, 7]
index: 0 1 2 3 4
Running Sums:
S[0] = 23
S[1] = 23+2 = 25
S[2] = 23+2+4 = 29
Remainders (mod 6):
R[0] = 23 % 6 = 5 (Seen at index 0) <--- Previous occurrence (prev_index = 0)
R[1] = 25 % 6 = 1 (Seen at index 1)
R[2] = 29 % 6 = 5 (Seen at index 2) <--- Current occurrence (current_index = 2)
Since R[2] == R[0]:
The sum of the subarray (nums[prev_index + 1] ... nums[current_index]) is a multiple of k.
Subarray: nums[0+1 ... 2] = nums[1 ... 2] = [2, 4]
Sum = 2 + 4 = 6.
6 % 6 = 0 (it's a multiple!)
Length condition: current_index - prev_index > 1
2 - 0 > 1 => 2 > 1 (True)
What if k = 0? If k is 0, the line runningSum %= k; is skipped. The map stores the actual runningSum values. If a runningSum repeats, it means the subarray between the two occurrences sums to 0. For example, if sum_j == sum_i, then sum_j - sum_i == 0. The condition i - prev > 1 still ensures the subarray has at least two elements.
The map.put(0, -1) explanation: This handles cases where a subarray starting from the beginning (index 0) sums to a multiple of k. Example: nums = [6, 1], k = 6
i = 0,nums[0] = 6.runningSum = 6.remainder = 6 % 6 = 0.- Is
remainder (0)inmap? Yes,map.get(0)givesprev = -1. - Check
i - prev > 1:0 - (-1) > 1=>1 > 1. This is FALSE. - So, we don’t return true yet. (This is because
[6]is a subarray of length 1, and the conditioni - prev > 1implies a length of at least 2 for the found subarray). map.put(0, 0)(Now0maps to0, overriding-1).
- Loop continues or ends. If no other subarray is found, it returns
false.
If nums = [2, 4], k = 6:
i = 0, nums[0] = 2.runningSum = 2.rem = 2.map = {0:-1, 2:0}.i = 1, nums[1] = 4.runningSum = 2+4=6.rem = 0.- Is
0inmap? Yes,prev = map.get(0)which is-1. - Check
i - prev > 1:1 - (-1) > 1=>2 > 1. This is TRUE. - Return
true. The subarraynums[(-1)+1 ... 1]which isnums[0...1](i.e.,[2,4]) sums to 6. Length is 2.
- Is
The i - prev > 1 condition is crucial for ensuring the identified subarray has a length of at least two. If a subarray of length one (a single element being a multiple of k) was also a valid solution, the condition would be i - prev >= 1.
