- Leetcode 523
- Difficulty: Medium
- Patterns:
Problem Definition
Given an integer array and an integer $k$, determine if there is a subarray of minimum length 2 whose sum is divisible by $k$.
Examples
Some test cases to verify our solution.
l = [15, 2, 4, 6, 7]
assert subarray_sum(l, 6)
assert not subarray_sum(l, 15)
assert subarray_sum(l, 12)
assert subarray_sum(l, 13)
assert not subarray_sum(l, 22)
assert subarray_sum(l, sum(l))
assert subarray_sum([23, 2, 4, 6, 6], 7)
assert not subarray_sum([1, 0], 2)
Solution
Suppose there's a subarray of the input array nums
with an inclusive start $i$ and inclusive end $j$ such
that $(\sum_{x=i}^j num_x) \mod\ k = 0$.
If $pref_i$ is the prefix sum up to and including index $i$ ($\sum_{x=0}^i num_x$), then: $$ (\sum_{x=i}^j num_x) = pref_j-pref_{i-1} $$ And therefore: $$ (\sum_{x=i}^j num_x) \mod\ k = 0 \implies (pref_j-pref_{i-1}) \mod k = 0 \implies pref_j \mod k = pref_{i - 1} \mod k $$
However, if we have an element $num_z = 0$, then $pref_z = pref_{z-1} + num_z = pref_{z-1} + 0 = pref_{z-1} \implies pref_z \mod k = pref_{z - 1} \mod k$. To catch this case, we must check that the prior prefix is at least two elements away in order to satisfy the problem's requirements.
Using this property, we'll store all remainders for each index's prefix sum as we traverse the array.
If we find an instance where the remainder has been previously encountered and if that remainder was encountered more
than one element ago, then we'll return True
.
If we don't find a matching remainder, then we'll return False
.
def subarray_sum(nums: list[int], k: int) -> bool:
if len(nums) < 2:
return False
rem = 0
rem_to_first_idx = {0: -1}
for idx, num in enumerate(nums):
rem = (num + rem) % k
if rem in rem_to_first_idx:
if rem_to_first_idx[rem] < idx - 1:
return True
else:
rem_to_first_idx[rem] = idx
return False
Complexity
Let $n = $ len(nums)
.
Since we're traversing the nums array once, the runtime complexity should be $\Theta(n)$.
Auxiliary space complexity should be $O(k)$ since in the worst case, we might store up to $k$ items in the
rem_to_first_idx
mapping.