Lessons
1 · Foundations (Think Like a Programmer)
2 · Data Structures and Recursion
- 05Arrays and Array-Based Problem Solving
- 06Strings: Characters, Immutability, and Efficient Manipulation
- 07Linked Lists: Nodes, Pointers, and Pointer Reasoning
- 08Stacks and Queues
- 09Hashing: HashMap, HashSet, and Frequency Patterns
- 10Recursion and Backtracking
- 11Trees and Binary Search Trees
- 12Heaps and Priority Queues
3 · Core Algorithms and Reusable Patterns
4 · Advanced Interview Topics
Lesson 16 · Core Algorithms and Reusable Patterns
Prefix Sums and Difference Arrays
Answer range-sum queries in constant time with a running-total array, count subarrays with a given sum using a hash map, compute product-except-self, handle 2D regions, and apply many range updates at once with a difference array.
For
Learners who know arrays and hashing and want an efficient way to answer many sum questions or apply many range updates.
Level
Before you start
Articles 5, 9 and 15: arrays, hash maps and sliding window. Knowing why sliding windows fail with negative numbers helps.
On this page
Key takeaways
- A prefix sum array stores running totals, so the sum of any range is one subtraction: prefix[right + 1] - prefix[left]. Build it once in O(n), then answer each query in O(1).
- Fix an index convention before you code. We use prefix[i] = the sum of the first i elements, so the array has length n + 1 and starts with 0.
- Prefix sums plus a hash map count subarrays with sum k, even with negative numbers, where sliding windows fail.
- A difference array is the reverse idea: a range update touches two entries, and a single prefix-sum pass rebuilds the final array.
- Use long for the totals. Sums of many int values overflow int easily.
Your bank statement shows a running balance after each transaction. Suppose you want to know how much you spent between the 10th and the 20th of the month. You do not add up eleven days of transactions. You take the balance after the 20th and subtract the balance before the 10th.
That subtraction trick is the whole idea behind prefix sums. If you store the running total once, then the total of any stretch of data is the difference of two stored numbers. It is the standard way to answer many "sum of a range" questions quickly, and it opens the door to a surprising number of subarray problems.
This article also covers the mirror image, the difference array, which makes it cheap to apply many range updates.
What you will learn
#- How to build a prefix sum array and answer range-sum queries in
O(1). - How to get the index convention right, so there are no off-by-one errors.
- How to combine prefix sums with a hash map to count subarrays with a given sum.
- Prefix and suffix products, and 2D prefix sums.
- How a difference array turns many range updates into
O(1)each.
The problem: many range-sum queries
#You are given an array a of n numbers and q queries. Each query gives two positions left and right, and asks for the sum of a[left..right], including both ends.
Brute force. For each query, loop from left to right and add. One query costs O(n), so q queries cost O(n × q). With n = q = 100,000 that is ten billion steps.
Prefix sums. Precompute the running totals once, in O(n). Each query is then a single subtraction, O(1), for a total of O(n + q).
Building the prefix array
#Here is the convention we will use throughout:
prefix[i]is the sum of the firstielements ofa, that isa[0] + ... + a[i - 1]. Soprefix[0] = 0(the sum of nothing), andprefixhas lengthn + 1.
Each entry builds on the one before it: prefix[i + 1] = prefix[i] + a[i].
With this convention:
The sum of
a[left..right](inclusive) equalsprefix[right + 1] - prefix[left].
Why? prefix[right + 1] is the total of everything from position 0 through right. prefix[left] is the total of everything from 0 through left - 1. Subtracting removes the part before left, leaving exactly a[left..right].
The leading 0 is not decoration. It makes the formula work when left = 0, because then we subtract prefix[0] = 0, and no special case is needed.
Dry run for a = [3, 1, 4, 1, 5, 9, 2, 6]:
|
|
|
|---|---|---|
start |
| |
0 | 3 | 3 |
1 | 1 | 4 |
2 | 4 | 8 |
3 | 1 | 9 |
4 | 5 | 14 |
5 | 9 | 23 |
6 | 2 | 25 |
7 | 6 | 31 |
So prefix = [0, 3, 4, 8, 9, 14, 23, 25, 31]. For the query left = 2, right = 5 (the elements 4, 1, 5, 9): prefix[6] - prefix[2] = 23 - 4 = 19, and indeed 4 + 1 + 5 + 9 = 19.
// File: Main.javaimport java.util.Arrays;public class Main { static class PrefixSum { private final long[] prefix; // prefix[i] = sum of the first i elements PrefixSum(int[] a) { prefix = new long[a.length + 1]; for (int i = 0; i < a.length; i++) { prefix[i + 1] = prefix[i] + a[i]; } } // Sum of a[left..right], both ends included. long sum(int left, int right) { if (left < 0 || right >= prefix.length - 1 || left > right) { throw new IndexOutOfBoundsException("bad range " + left + ".." + right); } return prefix[right + 1] - prefix[left]; } @Override public String toString() { return Arrays.toString(prefix); } } public static void main(String[] args) { int[] a = {3, 1, 4, 1, 5, 9, 2, 6}; PrefixSum ps = new PrefixSum(a); System.out.println(ps); System.out.println(ps.sum(2, 5) + " " + ps.sum(0, 7) + " " + ps.sum(4, 4) + " " + ps.sum(0, 0)); try { ps.sum(5, 2); } catch (IndexOutOfBoundsException e) { System.out.println("error: " + e.getMessage()); } int matches = 0; for (int left = 0; left < a.length; left++) { long brute = 0; for (int right = left; right < a.length; right++) { brute += a[right]; if (brute == ps.sum(left, right)) { matches++; } } } System.out.println(matches + " of 36 ranges match the brute force"); }}[0, 3, 4, 8, 9, 14, 23, 25, 31]19 31 5 3error: bad range 5..236 of 36 ranges match the brute forceComplexity: building is O(n) time and O(n) space. Each query is O(1).
Prefix sums work for static data. If the array changes between queries, you must rebuild (O(n)) or use a structure designed for updates, such as the Fenwick tree in Range Queries and Disjoint Set Union.
Subarray sum equals k
#Problem. Count the contiguous subarrays whose elements sum to k. The numbers may be negative. For [1, 2, 3] and k = 3, the answer is 2 (the subarrays [1, 2] and [3]).
Brute force. For each start, extend the end and keep a running sum: O(n^2).
Why not a sliding window? Because of negative numbers. As we saw in the last article, shrinking a window does not necessarily move the sum in a predictable direction.
Prefix sums. The sum of the subarray a[i..j] is prefix[j + 1] - prefix[i]. We want it to be k, which means prefix[i] = prefix[j + 1] - k. So, as we sweep j from left to right, keeping the current prefix total p, the question becomes: how many earlier prefix totals equal p - k? Each such earlier prefix is the start of a subarray ending here with sum k. A hash map from prefix value to the number of times it has occurred answers that in O(1).
One detail: the "empty prefix" with value 0 (before the first element) must be in the map from the start, with count 1. Otherwise subarrays that begin at position 0 would never be counted.
Dry run for [1, 2, 3], k = 3:
Element | Running prefix | Need | Count of | Total | Map after |
|---|---|---|---|---|---|
start | 0 | 0 |
| ||
1 | 1 | -2 | 0 | 0 |
|
2 | 3 | 0 | 1 (the empty prefix), so | 1 |
|
3 | 6 | 3 | 1 (the prefix before the | 2 |
|
// File: Main.javaimport java.util.HashMap;import java.util.Map;public class Main { // Brute force: O(n^2). static int countBrute(int[] a, int k) { int count = 0; for (int start = 0; start < a.length; start++) { long sum = 0; for (int end = start; end < a.length; end++) { sum += a[end]; if (sum == k) { count++; } } } return count; } // Prefix sums and a hash map: O(n) time, O(n) space, works with negative numbers. static int countWithMap(int[] a, long k) { Map<Long, Integer> seen = new HashMap<>(); seen.put(0L, 1); // the empty prefix long prefix = 0; int count = 0; for (int x : a) { prefix += x; count += seen.getOrDefault(prefix - k, 0); // earlier prefixes that make a sum of k seen.merge(prefix, 1, Integer::sum); } return count; } public static void main(String[] args) { int[][] inputs = {{1, 2, 3}, {1, 1, 1}, {3, 4, 7, 2, -3, 1, 4, 2}, {1, -1, 0}, {}}; int[] ks = {3, 2, 7, 0, 5}; for (int t = 0; t < inputs.length; t++) { System.out.println(countBrute(inputs[t], ks[t]) + " " + countWithMap(inputs[t], ks[t])); } }}2 22 24 43 30 0The input [1, -1, 0] with k = 0 has three subarrays that sum to zero ([1, -1], [1, -1, 0] and [0]), and it also contains negative numbers, which would have broken a sliding window. The map version handles it in O(n).
Prefix and suffix products
#The same idea works for products. Problem: for each position, return the product of all the other elements, without using division. For [1, 2, 3, 4] the answer is [24, 12, 8, 6].
The product of everything except a[i] is (product of everything to its left) times (product of everything to its right). Do two passes. Going left to right, keep a running product of the elements before i and store it in result[i]. Going right to left, keep a running product of the elements after i and multiply it into result[i].
We avoid division because the array may contain zeros, which makes division impossible, and because it is a common interview constraint.
// File: Main.javaimport java.util.Arrays;public class Main { static long[] productExceptSelf(int[] a) { int n = a.length; long[] result = new long[n]; long prefix = 1; for (int i = 0; i < n; i++) { result[i] = prefix; // product of everything before i prefix *= a[i]; } long suffix = 1; for (int i = n - 1; i >= 0; i--) { result[i] *= suffix; // multiply in the product of everything after i suffix *= a[i]; } return result; } public static void main(String[] args) { System.out.println(Arrays.toString(productExceptSelf(new int[] {1, 2, 3, 4}))); System.out.println(Arrays.toString(productExceptSelf(new int[] {1, 0, 3, 4}))); System.out.println(Arrays.toString(productExceptSelf(new int[] {0, 0, 2}))); System.out.println(Arrays.toString(productExceptSelf(new int[] {5}))); System.out.println(Arrays.toString(productExceptSelf(new int[] {}))); }}[24, 12, 8, 6][0, 12, 0, 0][0, 0, 0][1][]Time O(n), and extra space O(1) beyond the output array. Products grow fast, so even a long can overflow for long arrays of large numbers. A real problem would state limits that keep the answer in range, and you should ask.
Two-dimensional prefix sums
#For a grid, let P[r][c] be the sum of the rectangle from the top-left corner (0, 0) to (r - 1, c - 1). Again we use an extra row and column of zeros. Build it with inclusion and exclusion:
P[r + 1][c + 1] = m[r][c] + P[r][c + 1] + P[r + 1][c] - P[r][c]
(the cell itself, plus the rectangle above, plus the rectangle to the left, minus the overlap that was counted twice).
The sum of any rectangle with corners (r1, c1) and (r2, c2) is then:
P[r2 + 1][c2 + 1] - P[r1][c2 + 1] - P[r2 + 1][c1] + P[r1][c1]
(the big rectangle, minus the strip above it, minus the strip to its left, plus back the corner that was removed twice).
// File: Main.javapublic class Main { static class NumMatrix { private final long[][] p; NumMatrix(int[][] m) { int rows = m.length; int cols = rows == 0 ? 0 : m[0].length; p = new long[rows + 1][cols + 1]; for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { p[r + 1][c + 1] = m[r][c] + p[r][c + 1] + p[r + 1][c] - p[r][c]; } } } long sumRegion(int r1, int c1, int r2, int c2) { return p[r2 + 1][c2 + 1] - p[r1][c2 + 1] - p[r2 + 1][c1] + p[r1][c1]; } } public static void main(String[] args) { int[][] grid = { {3, 0, 1, 4, 2}, {5, 6, 3, 2, 1}, {1, 2, 0, 1, 5}, {4, 1, 0, 1, 7}, {1, 0, 3, 0, 5} }; NumMatrix nm = new NumMatrix(grid); System.out.println(nm.sumRegion(2, 1, 4, 3)); System.out.println(nm.sumRegion(1, 1, 2, 2)); System.out.println(nm.sumRegion(1, 2, 2, 4)); System.out.println(nm.sumRegion(0, 0, 4, 4)); }}8111258Building takes O(rows × cols), and each query takes O(1). Check the first answer by hand: rows 2 to 4 and columns 1 to 3 hold 2, 0, 1, then 1, 0, 1, then 0, 3, 0, which add up to 8.
Difference arrays: the reverse idea
#Prefix sums turn "many range sums" into cheap queries. A difference array turns "many range updates" into cheap updates.
Problem. You have an array of n zeros. You are given many updates, each saying "add v to every element from position l to position r". After all updates, output the final array.
Brute force. Each update loops over its range: O(n) per update, so O(n × u) for u updates.
Difference array. Instead of tracking the values, track the changes between neighbours: diff[i] = a[i] - a[i - 1]. Now consider the effect of adding v to the range [l, r]:
- the jump into the range at position
lgrows byv, sodiff[l] += v; - the jump out of the range at position
r + 1shrinks byv, sodiff[r + 1] -= v; - all differences inside the range stay the same.
That is two array writes per update, no matter how long the range. After all updates, one pass of prefix sums over diff rebuilds the real array: a[i] = diff[0] + ... + diff[i]. We make diff one slot longer than a so that r + 1 is always a valid index.
Example. Flight bookings: there are n flights. Each booking [first, last, seats] reserves seats seats on every flight from first to last (flights are numbered from 1). Return the total seats booked on each flight. With n = 5 and bookings [1, 2, 10], [2, 3, 20], [2, 5, 25], the answer is [10, 55, 45, 25, 25].
Convert to 0-based positions and apply the updates:
Booking | 0-based range | Changes to |
|
|---|---|---|---|
start |
| ||
| 0 to 1 |
|
|
| 1 to 2 |
|
|
| 1 to 4 |
|
|
Now take running totals of diff: 10, 55, 45, 25, 25 (the last slot, -25, is only the sentinel).
// File: Main.javaimport java.util.Arrays;public class Main { static long[] buildDiff(int[][] bookings, int n) { long[] diff = new long[n + 1]; // one extra slot for the "r + 1" write for (int[] b : bookings) { int first = b[0] - 1; // convert 1-based flight numbers to 0-based int last = b[1] - 1; diff[first] += b[2]; diff[last + 1] -= b[2]; } return diff; } static long[] totals(int[][] bookings, int n) { long[] diff = buildDiff(bookings, n); long[] answer = new long[n]; long running = 0; for (int i = 0; i < n; i++) { running += diff[i]; // a prefix sum over the differences answer[i] = running; } return answer; } public static void main(String[] args) { int[][] bookings = {{1, 2, 10}, {2, 3, 20}, {2, 5, 25}}; System.out.println(Arrays.toString(buildDiff(bookings, 5))); System.out.println(Arrays.toString(totals(bookings, 5))); System.out.println(Arrays.toString(totals(new int[][] {{1, 2, 10}, {2, 2, 15}}, 2))); System.out.println(Arrays.toString(totals(new int[][] {}, 3))); }}[10, 45, -10, -20, 0, -25][10, 55, 45, 25, 25][10, 25][0, 0, 0]Complexity: each update is O(1), so u updates cost O(u), plus one O(n) pass to rebuild. The total is O(n + u) instead of O(n × u). Prefix sums and difference arrays are inverses of each other: a prefix sum turns differences into values, and a difference turns values into differences.
Complexity summary
#Task | Build | Each query or update | Space |
|---|---|---|---|
Range sum with prefix array | O(n) | O(1) | O(n) |
Subarray sum equals | n/a | O(n) total | O(n) |
Product except self | n/a | O(n) total | O(1) beyond the output |
2D region sum | O(rows × cols) | O(1) | O(rows × cols) |
Range update with difference array | O(1) per update | O(n) once, to read the final array | O(n) |
Edge cases and common mistakes
#- Index convention confusion. Decide: is
prefix[i]the sum of the firstielements (lengthn + 1, starts with 0), or up to and includingi? Use one, and write it in a comment. With our convention the range sum isprefix[right + 1] - prefix[left]. - Forgetting the leading zero in the prefix array, or forgetting to put
0 -> 1in the hash map for "subarray sum equalsk". intoverflow. Uselongfor prefix totals and products.- Querying with
left > rightor out-of-range positions. Validate, or document the assumption. - Writing
diff[r + 1]without an extra slot. The array must haven + 1entries. - 1-based versus 0-based input. Flight numbers, positions and ranges in problem statements are often 1-based. Convert once, at the boundary.
- Using prefix sums when the array changes. They are for static data.
- Assuming a sliding window works for exact sums with negatives. It does not. Use prefix sums and a map.
- Division in product-except-self. It fails for zeros and may overflow. Use prefix and suffix products.
Exercises
#Exercise 1
Trace
#Build the prefix array for [2, -1, 3, 5]. Use it to compute the sum of positions 1 to 3, and of positions 0 to 0. Show the subtractions.
Exercise 2: Pivot index
#The pivot index is a position where the sum of the elements strictly to its left equals the sum of the elements strictly to its right (an empty side counts as 0). Return the leftmost pivot index, or -1. For [1, 7, 3, 6, 5, 6] the answer is 3.
Exercise 3: Range addition
#Start with n = 5 zeros. Apply the updates [l, r, v] (0-based, both ends included, add v to every position in the range): [1, 3, 2], [2, 4, 3], [0, 2, -2]. Return the final array using a difference array.
Exercise 4: Debug
#This range-sum class gives the wrong answer for some queries, and crashes for others. Find the problems and fix them.
class BuggyPrefix { private final int[] prefix; BuggyPrefix(int[] a) { prefix = new int[a.length]; prefix[0] = a[0]; for (int i = 1; i < a.length; i++) { prefix[i] = prefix[i - 1] + a[i]; } } int sum(int left, int right) { return prefix[right] - prefix[left]; }}Exercise 5: Interview-style, subarrays divisible by K
#Count the contiguous subarrays whose sum is divisible by K. For [4, 5, 0, -2, -3, 1] and K = 5, the answer is 7. The array may contain negative numbers.
Show solutionHide solution
The prefix array has length 5: prefix[0] = 0, prefix[1] = 2, prefix[2] = 2 + (-1) = 1, prefix[3] = 1 + 3 = 4, prefix[4] = 4 + 5 = 9. So prefix = [0, 2, 1, 4, 9].
- Sum of positions 1 to 3 (
-1, 3, 5):prefix[4] - prefix[1] = 9 - 2 = 7. Check:-1 + 3 + 5 = 7. ✓ - Sum of positions 0 to 0 (just
2):prefix[1] - prefix[0] = 2 - 0 = 2. ✓
Notice how the leading 0 handles the query that begins at position 0.
Exercise 2
Show solutionHide solution
Let total be the sum of all elements. At position i, if leftSum is the sum of the elements before it, then the sum to its right is total - leftSum - a[i]. A pivot is where leftSum == total - leftSum - a[i]. Keep leftSum as a running total, so no second array is needed. Time O(n), space O(1). Use long for the sums.
// File: Main.javapublic class Main { static int pivotIndex(int[] a) { long total = 0; for (int x : a) { total += x; } long leftSum = 0; for (int i = 0; i < a.length; i++) { if (leftSum == total - leftSum - a[i]) { return i; } leftSum += a[i]; } return -1; } public static void main(String[] args) { System.out.println(pivotIndex(new int[] {1, 7, 3, 6, 5, 6})); System.out.println(pivotIndex(new int[] {1, 2, 3})); System.out.println(pivotIndex(new int[] {2, 1, -1})); System.out.println(pivotIndex(new int[] {})); System.out.println(pivotIndex(new int[] {5})); }}3-10-10For [1, 7, 3, 6, 5, 6], total = 28. At index 3: leftSum = 11 and the right side is 28 - 11 - 6 = 11, so the pivot is 3. For [2, 1, -1], index 0 has an empty left side (0) and a right side of 1 + (-1) = 0, so the answer is 0. A single-element array always has a pivot at index 0 (both sides are empty).
Exercise 3
Show solutionHide solution
Allocate diff of length n + 1. For each update [l, r, v], do diff[l] += v and diff[r + 1] -= v. Then take running sums.
Update | Changes |
|
|---|---|---|
start |
| |
|
|
|
|
|
|
|
|
|
Running totals: -2, 0, 3, 5, 3.
// File: Main.javaimport java.util.Arrays;public class Main { static long[] applyUpdates(int n, int[][] updates) { long[] diff = new long[n + 1]; for (int[] u : updates) { diff[u[0]] += u[2]; diff[u[1] + 1] -= u[2]; } long[] result = new long[n]; long running = 0; for (int i = 0; i < n; i++) { running += diff[i]; result[i] = running; } return result; } public static void main(String[] args) { System.out.println(Arrays.toString(applyUpdates(5, new int[][] {{1, 3, 2}, {2, 4, 3}, {0, 2, -2}}))); System.out.println(Arrays.toString(applyUpdates(3, new int[][] {{0, 2, 7}}))); System.out.println(Arrays.toString(applyUpdates(0, new int[][] {}))); }}[-2, 0, 3, 5, 3][7, 7, 7][]The final array is [-2, 0, 3, 5, 3]. Cross-check position 2: it receives +2 (first update), +3 (second) and -2 (third), which adds up to 3. ✓
Exercise 4
Show solutionHide solution
The problems:
- Wrong formula.
prefix[right] - prefix[left]leaves outa[left]. With this definition (prefix[i]includesa[i]), the sum ofa[left..right]isprefix[right] - prefix[left - 1], and forleft = 0it is justprefix[right], which needs a special case. That special case is exactly what the leading zero removes. prefix[0] = a[0]crashes on an empty array, becauseprefixhas length 0.inttotals can overflow. Uselong.
Fix by using the n + 1 convention from the article.
// File: Main.javapublic class Main { static class BuggyPrefix { private final int[] prefix; BuggyPrefix(int[] a) { prefix = new int[a.length]; prefix[0] = a[0]; for (int i = 1; i < a.length; i++) { prefix[i] = prefix[i - 1] + a[i]; } } int sum(int left, int right) { return prefix[right] - prefix[left]; } } static class FixedPrefix { private final long[] prefix; FixedPrefix(int[] a) { prefix = new long[a.length + 1]; for (int i = 0; i < a.length; i++) { prefix[i + 1] = prefix[i] + a[i]; } } long sum(int left, int right) { return prefix[right + 1] - prefix[left]; } } public static void main(String[] args) { int[] a = {3, 1, 4, 1, 5}; System.out.println("buggy sum(0, 2) = " + new BuggyPrefix(a).sum(0, 2) + ", fixed = " + new FixedPrefix(a).sum(0, 2)); System.out.println("buggy sum(1, 3) = " + new BuggyPrefix(a).sum(1, 3) + ", fixed = " + new FixedPrefix(a).sum(1, 3)); try { new BuggyPrefix(new int[] {}); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("buggy constructor crashes on an empty array"); } }}buggy sum(0, 2) = 5, fixed = 8buggy sum(1, 3) = 5, fixed = 6buggy constructor crashes on an empty arrayThe correct sums are 3 + 1 + 4 = 8 for positions 0 to 2, and 1 + 4 + 1 = 6 for positions 1 to 3. The buggy version returns 5 and 5, because it drops the element at left (the 3 in the first query and the 1 in the second).
Exercise 5
Show solutionHide solution
Two prefixes prefix[i] and prefix[j] (with i < j) give a subarray sum prefix[j] - prefix[i]. That difference is divisible by K exactly when the two prefixes have the same remainder modulo K. So: count, for each remainder, how many prefixes have it. Each pair of prefixes with the same remainder is one valid subarray.
Sweep through the array keeping the running remainder. Before processing, the empty prefix has remainder 0, so count[0] = 1. At each element, update the remainder, add count[remainder] to the answer (every earlier prefix with the same remainder gives a subarray), then increment count[remainder].
Negative numbers. In Java, % can return a negative remainder (-3 % 5 = -3). Use Math.floorMod(x, K) to get a remainder in 0..K-1, so equal remainders really are equal. Time O(n), space O(K).
// File: Main.javapublic class Main { static int subarraysDivByK(int[] a, int k) { int[] count = new int[k]; count[0] = 1; // the empty prefix has remainder 0 int remainder = 0; int answer = 0; for (int x : a) { remainder = Math.floorMod(remainder + x, k); answer += count[remainder]; count[remainder]++; } return answer; } public static void main(String[] args) { System.out.println(subarraysDivByK(new int[] {4, 5, 0, -2, -3, 1}, 5)); System.out.println(subarraysDivByK(new int[] {5}, 9)); System.out.println(subarraysDivByK(new int[] {5}, 5)); System.out.println(subarraysDivByK(new int[] {-1, 2, 9}, 2)); System.out.println(subarraysDivByK(new int[] {}, 3)); }}70120The running remainders for the first example are 4, 4, 4, 2, 4, 0 (after each element), and with the initial 0: remainder 4 appears four times (so C(4, 2) = 6 pairs) and remainder 0 appears twice (the initial one and the last, so 1 pair), giving 6 + 1 = 7 subarrays. The method remainder + x cannot overflow here, since remainder < k and x is a normal value, but use long if both can be near the int limit.
Where to go next
#- Next: Greedy Algorithms and Interval Problems deals with ranges again, but asks for the best way to choose or merge them.
- Later: Range Queries and Disjoint Set Union shows what to do when the array changes between queries (Fenwick and segment trees).
- Practice habit: every time you see "sum of a range", "number of subarrays with ...", or "apply updates to ranges", ask whether a prefix sum or a difference array fits before you write a loop.
Connected lessons
Linked from 5 guides
Other pages in the library that point here.
Keep reading
More in Technology →Guide · Technology
How to Learn Data Structures and Algorithms Without Burning Out
Guide · Career
The OA Landscape: Platforms, Formats, Proctoring and Rules
Guide · Career
A LinkedIn Profile That Gets Recruiter Messages

