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.
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.
Example 2:
Input: nums = [23,2,6,4,7], k = 6
Output: true
Explanation: [23, 2, 6, 4, 7] is an continuous subarray of size 5 whose elements sum up to 42.
42 is a multiple of 6 because 42 = 7 * 6 and 7 is an integer.
Example 3:
Input: nums = [23,2,6,4,7], k = 13
Output: false
Playground: Leetcode 523
Naive Approach - Nested Loops
Iterate over all possible substrings, maintain a running sum for each and return true if any of the
subarray's sum is divisible by k.
Algorithm
1. Iterate over each index in "nums", treating it as the starting index for the current subarray.
2. Initialize a variable: "currentSubarraySum" to track the cumulative sum of the current subarray.
3. For each starting index, expand the subarray one element at a time.
4. Add the current element to "currentSubarraySum".
5. If the length of the current substring is greater than 1 and "currentSubarraySum" is completely
divisible by "k", return "true".
6. If no good subarray found, return "false".
Implementation
Time Complexity
In the worst-case scenario, i.e, when no good subarray exists, we will explore all possible subarrays of
nums.
The operations inside the inner loop mainly involve arithmetic calculations like addition and
division, all consuming constant time, O(1). Therefore, the time complexity is primarily dependent on
the number of times the inner loop is executed.
The outer loop will run n times. For every ith iteration, the inner loop will run for (n - i) times.
The total number of iterations performed will be:
(n-0) + (n-1) + (n-2) + (n-3) + ... + (n-(n-1))
= n + (n - 1) + ... 3 + 2 + 1
= [n x (n+1)] / 2
Since, the total number inner-loop executions grow proportional to n², the overall time
complexity is O(n²).
Space Complexity
We only use one variable, currentSubarraySum, to keep track of the cumulative sum of the current subarray.
Since we do not use any additional data structures, the overall space complexity is O(1).
Key Observations
For a subarray (j+1 ... i) to have a sum divisible by k, (prefixSum[i] - prefixSum[j]) % k == 0.

In other words, if: prefixSum[i] % k == prefixSum[j] % k, then the subarray (j+1 ... i) has a sum divisible
by k. This observation essentially changes the problem from checking every subarray to checking whether we've
seen the same prefix-sum remainder before.
Suitable Approach - Prefix Sum
Iterate over nums while maintaining a map of prefix-sum-remainders. Return true if a remainder is
seen again and the difference between the current index and its first occurrence is greater than 1.
-
We store the first occurrence of each prefix-sum remainder to ensure that we can find the longest possible subarray ending at the current index.
-
To handle good subarrays that start at index
0, initialize the map with a prefix-sum-remainder of0at index-1.
Algorithm
1. Initialize:
a. A map: "prefixSumRemainderMap" to track the first occurrence of every distinct
prefix-sum-remainder.
b. A variable: "currentPrefixSum" to track the prefix sum observed so far.
2. Add "{0, -1}" to "prefixSumRemainderMap" to handle good subarrays that start at index `0`.
3. Iterate over each "index" in "nums".
4. Add the current element: "nums[index]" to "currentPrefixSum".
5. Calculate "currentPrefixSumRemainder".
6. If "prefixSumRemainderMap" contains "currentPrefixSumRemainder" and the difference
between the current index and first occurence of "currentPrefixSumRemainder" is
greater than "1", return "true".
7. If "prefixSumRemainderMap" does not contain "currentPrefixSumRemainder", add
"currentPrefixSumRemainder" and the current index as key-value pair in
"prefixSumRemainderMap".
8. If no good subarray found, return "false".
Implementation
Time Complexity
For each iteration, we perform only a few arithmetic operations and validation checks, all
of which take constant time, O(1). Therefore, the time complexity primarily depends on the
number of iterations.
In the worst-case scenario, i.e., when no good subarray exists, the loop executes n times.
Hence, the overall time complexity is O(n).
Space Complexity
We use a map to store the first occurrence of each distinct prefix-sum remainder.
In the worst case, all prefix-sum remainders are distinct, so the map will contain n key-value pairs.
Hence, the overall space complexity is O(n).