Continuous Subarray Sum

MediumPrefix Sum · Hash Map (Modulo)🧩 Prefix SumLeetCode #523 ↗Updated

Problem

Given a non-negative integer array nums and a positive integer k, decide whether some contiguous subarray of length at least 2 has a sum that is a multiple of k (zero counts as a multiple). Return true or false.
Inputnums = [23,2,4,6,7], k = 6Outputtrue ([2,4] sums to 6)
Inputnums = [23,2,6,4,7], k = 6Outputtrue (whole array sums to 42)
Inputnums = [23,2,6,4,7], k = 13Outputfalse

1 ≤ n ≤ 105  ·  0 ≤ nums[i] ≤ 109  ·  total sum ≤ 231-1  ·  1 ≤ k ≤ 231-1

Try it yourself

Java
class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
A subarray (i, j] sums to a multiple of k exactly when the prefix sums at i and j leave the same remainder mod k. Remember the earliest index of each remainder and check that the gap is at least 2.
PatternPrefix Sum

Instinct Repeated range-sum queries, or "count subarrays whose sum equals / divides K" with negatives allowed? Store running totals and subtract two of them.

Memory hack Any range is two prefixes apart - sum(i..j) = P[j+1] - P[i], so remember every P you've passed.

Open the Prefix Sum guide →

Approaches

Brute ForceAll Subarrays with Running Sum

Time O(n2)Space O(1)

Fix a start index and extend the end, maintaining the running sum. As soon as a window of length ≥ 2 has sum % k == 0, we are done. A running sum avoids re-adding the window each time.

Java
public boolean checkSubarraySum(int[] nums, int k) {
    int n = nums.length;
    for (int start = 0; start < n; start++) {
        long sum = nums[start];
        for (int end = start + 1; end < n; end++) {
            sum += nums[end];
            if (sum % k == 0) return true; // length >= 2 guaranteed
        }
    }
    return false;
}

Obviously correct, but quadratic — times out at n = 105.

At a glance

LevelApproachTimeSpace
Brute ForceAll Subarrays with Running SumO(n2)O(1)
OptimalPrefix Remainder → Earliest IndexO(n)O(min(n, k))
Common pitfalls
  • Forgetting the {0: -1} seed — misses subarrays that start at index 0.
  • Updating the stored index on every hit — breaks the length ≥ 2 check (e.g. [5,0,0]).
  • Treating a single element divisible by k as valid — length must be ≥ 2.
Interview tips
  • Derive it: (P[j] - P[i]) % k == 0 ⇔ P[j] % k == P[i] % k.
  • Explain why a map (index) is needed instead of a set: the length constraint.
  • Mention handling negatives with ((x % k) + k) % k if inputs could be negative.
Pattern
Prefix sum + remainder map → subarray sums that must be divisible by k, with a length condition.
My notes saved in this browser