523. Continuous Subarray Sum - Explanation
Description
You are 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:
- 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: trueExplanation: [2,4] is a continuous subarray of size 2 whose sum is 6.
Example 2:
Input: nums = [23,2,6,4,7], k = 6
Output: trueExplanation: [23,2,6,4,7] is an continuous subarray of size 5 whose sum is 42, which is a multiple of 6..
Example 3:
Input: nums = [23,2,6,4,7], k = 13
Output: falseConstraints:
1 <= nums.length <= 1,00,0000 <= nums[i] <= 1,000,000,0000 <= sum(nums) <= ((2^31)-1)1 <= k <= ((2^31)-1)
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Hash Map - Used for O(1) lookups to store and retrieve the first occurrence of each remainder value
- Prefix Sum - Computing cumulative sums to efficiently determine subarray sums
- Modular Arithmetic - Understanding how remainders work and that equal remainders at two indices indicate a sum divisible by k
1. Brute Force
Intuition
The straightforward approach is to check every possible subarray of size at least 2 and see if its sum is a multiple of k. A number is a multiple of k if dividing it by k leaves no remainder. We iterate through all starting and ending positions to examine every valid subarray.
Algorithm
- Iterate through all possible starting indices
ifrom0ton-2(we need at least 2 elements). - For each starting index, maintain a running sum starting with
nums[i]. - Extend the subarray by iterating through ending indices
jfromi+1ton-1, adding each element to the running sum. - After adding each element, check if the sum is divisible by
k(sum % k == 0). - If we find such a subarray, return
trueimmediately. - If no valid subarray is found after checking all possibilities, return
false.
Time & Space Complexity
- Time complexity:
- Space complexity:
2. Prefix Sum + Hash Map
Intuition
The key insight is based on modular arithmetic. If the prefix sum up to index i has remainder r when divided by k, and the prefix sum up to index j also has remainder r, then the subarray from i+1 to j has a sum that is a multiple of k. This is because (prefixSum[j] - prefixSum[i]) % k = 0 when both have the same remainder. We use a hash map to store the first index where each remainder was seen.
Algorithm
- Create a hash map to store remainder values and their first occurrence index. Initialize it with
{0: -1}to handle cases where the prefix sum itself is divisible byk. - Maintain a running total as we iterate through the array.
- For each element, add it to the total and compute the remainder (
total % k). - If this remainder exists in the map and the subarray length is at least 2 (current index minus stored index > 1), return
true. - If the remainder is not in the map, store it with the current index.
- Return
falseif no valid subarray is found.
class Solution:
def checkSubarraySum(self, nums: List[int], k: int) -> bool:
remainder = {0: -1} # remainder -> end index
total = 0
for i, num in enumerate(nums):
total += num
r = total % k
if r not in remainder:
remainder[r] = i
elif i - remainder[r] > 1:
return True
return FalseTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the size of the array and is the number that a subarray sum needs to be multiple of.
Common Pitfalls
Forgetting to Initialize Hash Map with {0: -1}
The hash map must be initialized with remainder 0 at index -1 to handle cases where the prefix sum itself (from index 0 to current) is divisible by k. Without this, you miss valid subarrays that start from index 0.
# Wrong - misses subarrays starting at index 0
remainder = {}
# Correct
remainder = {0: -1}Not Enforcing Minimum Subarray Length of 2
The problem requires the subarray to have at least 2 elements. A common mistake is checking i - remainder[r] >= 1 instead of > 1, which would accept single-element subarrays.
# Wrong - accepts single-element subarrays
elif i - remainder[r] >= 1:
# Correct - ensures at least 2 elements
elif i - remainder[r] > 1:Updating the Hash Map When Remainder Already Exists
When the same remainder is seen again, you should NOT update its index. We need the earliest index for each remainder to maximize the subarray length and correctly detect valid subarrays. Updating would shrink the window and potentially miss valid answers.
Sign in to join the discussion