Kadane, sliding window and two pointers, step by step
Four techniques turn "check every subarray" into a single pass over the array. Paste your own numbers, pick a technique and step through it: the window, the pointers and the running values move one decision at a time, and every answer is checked against brute force on the same input.
best = cur = a[0]
for i in 1..n-1:
cur = max(a[i], cur + a[i]) # extend or start fresh
best = max(best, cur)
return bestProblem: Largest sum of a contiguous subarray.
Press Step or Play to start.
- Not started
- –
| This technique | 9 |
| Brute force | 45 |
Counted in subarray sums computed. Brute force computes the sum of every subarray and gets the same answer (6).
- Start at index 0: the best subarray so far is [-2] with sum -2
- i = 1: cur + 1 = -1 is less than 1 alone, so the run so far is dropped and a new one starts at index 1; that beats the best, now 1 for [1]
- i = 2: extending the run by -3 gives cur = -2
- i = 3: cur + 4 = 2 is less than 4 alone, so the run so far is dropped and a new one starts at index 3; that beats the best, now 4 for [4]
- i = 4: extending the run by -1 gives cur = 3
- i = 5: extending the run by 2 gives cur = 5; that beats the best, now 5 for [4, -1, 2]
- i = 6: extending the run by 1 gives cur = 6; that beats the best, now 6 for [4, -1, 2, 1]
- i = 7: extending the run by -5 gives cur = 1
- i = 8: extending the run by 4 gives cur = 5
How to use the visualizer
Pick a technique, then type or paste an array of integers separated by commas or spaces, along with the window size or target the technique needs. Step makes one decision at a time; Play runs them all. The tinted cells are the current window (for two pointers, the part of the array still in play) and the green cells are the best answer found so far. The panel on the right shows the running values and the full trace.
- Each technique opens with a standard example; Load the example brings it back after you edit.
- Copy answer gives the numbered trace and the result as plain text; Copy link saves the technique, array, target and step in the address.
The brute-force baseline
Many array problems ask about contiguous subarrays (the largest sum, the shortest run reaching a total, how many add up to k) or about pairs of elements. The direct solution tries them all. An array of n elements has n(n + 1)/2 non-empty subarrays and n(n − 1)/2 pairs, so brute force grows with the square of n:
| n | Subarrays (brute force) | Kadane's steps |
|---|---|---|
| 10 | 55 | 10 |
| 100 | 5,050 | 100 |
| 1,000 | 500,500 | 1,000 |
| 10,000 | 50,005,000 | 10,000 |
The techniques on this page each find a property of the problem that lets one pass replace the double loop: a running value that summarises everything to the left, a window whose sum changes predictably, or a sorted order that rules out many pairs per comparison. Each run above is checked against the brute-force answer, and on 10,000 random numbers the difference looks like this:
| Problem | Technique | Brute force | Counted in |
|---|---|---|---|
| Kadane, maximum subarray | 10,000 | 50,005,000 | subarray sums computed |
| Sliding window, k = 100 | 19,899 | 980,199 | additions and subtractions |
| Variable window, sum ≥ 1,000 | 19,960 | 50,005,000 | pointer moves |
| Two pointers, pair summing to 7 | 722 | 49,995,000 | pairs compared |
| Prefix sums, subarrays summing to 25 | 10,000 | 50,005,000 | subarray sums checked |
Kadane's algorithm
The maximum subarray problem asks for the contiguous run with the largest sum. In Programming Pearls, Jon Bentley tells its history: Ulf Grenander of Brown University posed it as a simplified, one-dimensional version of a pattern-matching problem on digitised images; Michael Shamos found a faster divide-and-conquer solution and described the problem at a Carnegie Mellon seminar, where the statistician Jay Kadane came up with the linear algorithm within a minute.
The idea is to ask, for each position i, what the best subarray ending at i is. It is either a[i] alone or a[i] added to the best subarray ending at i − 1, whichever is larger: cur = max(a[i], cur + a[i]). Put another way, a run with a negative sum is never worth extending, so the algorithm drops it and starts again. The overall answer is the largest cur seen. On [-2, 1, -3, 4, -1, 2, 1, -5, 4], the run restarts at 1 and again at 4, then grows to 6 over [4, -1, 2, 1] and never beats that. Kadane takes 9 steps; brute force computes 45 subarray sums.
Starting with best = a[0], as here, makes an all-negative array return its largest element: [-3, -1, -2] gives -1. Many write-ups start from 0 instead, which silently allows an empty subarray with sum 0. Which is right depends on how the problem is worded. Kadane's algorithm is also a small example of dynamic programming: cur is the answer to a subproblem, and each answer is built from the previous one.
Sliding window
A sliding window keeps a contiguous range [lo, hi] and a summary of it, usually its sum, and updates the summary as the ends move instead of recomputing it. With a fixed size k, sliding one place right adds the element entering and subtracts the one leaving, so each window costs two operations instead of k − 1 additions. On [1, 4, 2, 10, 23, 3, 1, 0, 20] with k = 4 the best window sums to 39, found with 13 additions and subtractions against 18 for summing every window from scratch. The saving grows with k: with k = 100 on 10,000 numbers it is 19,899 against 980,199.
A variable window grows and shrinks. For the shortest subarray with sum at least a target, move hi right, adding elements, until the sum reaches the target; then move lo right, removing elements, while it still does, recording the length each time. Each pointer only moves forward, so there are at most 2n moves. On [2, 3, 1, 2, 4, 3] with target 7 the answer is 2, the pair [4, 3], after 11 pointer moves.
The variable window depends on every number being positive: then growing the window always raises the sum and shrinking always lowers it, so once a window is too small, no window starting further left and ending at the same place can be shorter and still qualify. With a negative number that reasoning breaks. On [1, -2, 4] with target 3, the window method reports length 3, but [4] on its own reaches the target, so the answer is 1. The visualizer refuses to run the variable window on arrays with zero or negative numbers for this reason; prefix sums are the tool for those.
Two pointers
To find two numbers that add up to a target, sort the array and put one pointer at each end. If the two numbers add up to too little, the left one is too small to pair with anything that remains, because it is already paired with the largest remaining number; move it right. If the sum is too big, the right one is too large for anything that remains; move it left. Each comparison rules out every remaining pair that uses one of the two elements, which is why at most n − 1 comparisons are needed. For [2, 7, 11, 15] and target 9 that is 3 comparisons out of 6 pairs; on 10,000 numbers, 722 against 49,995,000.
Sorting costs O(n log n), so the whole method is O(n log n). If the array is unsorted and the original positions matter, a hash map of the numbers seen so far finds the pair in one O(n) pass instead. The same converging-pointer idea appears in reversing an array, checking a palindrome and the three-sum problem, which fixes one number and runs two pointers over the rest.
Prefix sums and a hash map
The prefix sum P[j] is the sum of the first j elements, with P[0] = 0. Any subarray sum is then a difference of two prefix sums: a[i] + … + a[j] = P[j + 1] − P[i]. A subarray ending at j sums to k exactly when some earlier prefix equals P[j + 1] − k. Keeping a hash map from each prefix sum to the number of times it has appeared turns the question "how many subarrays end here and sum to k" into one lookup.
The map starts as {0: 1}, for the empty prefix, so subarrays that start at index 0 are counted. On [1, 2, 1, -1, 2, 3] with k = 3, the run finds 4 subarrays in 6 lookups, where brute force checks 21 subarrays. Unlike the sliding window this does not care about signs, because it never assumes that a longer subarray has a larger sum. The cost is O(n) extra memory for the map.
Which technique to use
| Problem | Technique | Time | Needs |
|---|---|---|---|
| Largest subarray sum | Kadane | O(n) | Nothing |
| Best window of fixed size k | Fixed sliding window | O(n) | Nothing |
| Shortest or longest subarray meeting a sum limit | Variable sliding window | O(n) | Positive numbers |
| Pair adding up to a target | Two pointers | O(n log n) | Sorting allowed |
| Count subarrays with sum k | Prefix sums + hash map | O(n) | O(n) memory |
In interviews the clue is often in the wording. "Contiguous" or "subarray" points to a window, Kadane or prefix sums; "sorted" or "pair" points to two pointers. If the numbers can be negative, rule out the variable window first.
Array technique questions and answers
What is Kadane's algorithm?
A one-pass algorithm for the maximum subarray problem: the largest sum of a contiguous run of numbers. It keeps the best sum of a run ending at the current element, cur = max(a[i], cur + a[i]), and the best seen anywhere. For [-2, 1, -3, 4, -1, 2, 1, -5, 4] it finds 6, from [4, -1, 2, 1], in 9 steps where checking every subarray takes 45.
What is the time complexity of Kadane's algorithm?
O(n) time and O(1) extra space: it looks at each element once and keeps two numbers. Checking every subarray takes n(n + 1)/2 sums, 50,005,000 for 10,000 numbers against 10,000 for Kadane.
What does Kadane return if all the numbers are negative?
The largest single element, as long as it starts from best = a[0] rather than 0. For [-3, -1, -2] the answer is -1. Versions that start from 0 return 0, which is only right if the problem allows an empty subarray.
Why does the sliding window fail with negative numbers?
The variable window shrinks from the left once the sum is big enough, assuming that removing an element makes the sum smaller. A negative number breaks that. On [1, -2, 4] with target 3, the window reports a shortest length of 3, but [4] alone has length 1. Prefix sums handle negatives.
What is the difference between two pointers and a sliding window?
A sliding window is a kind of two pointers where both move in the same direction and the elements between them form the current subarray. In the classic two-pointer search on a sorted array, the pointers start at opposite ends and move toward each other, and only the two elements they point at matter.
How do you count subarrays with sum k?
Keep a running prefix sum p and a hash map of how many times each prefix sum has appeared, starting with {0: 1}. At each element, every earlier prefix equal to p − k starts a subarray that ends here and sums to k, so add the map's count for p − k. [1, 2, 1, -1, 2, 3] with k = 3 has 4. It works with negative numbers and runs in O(n).
Further reading
- Jon Bentley, Addison-WesleyProgramming Pearls, column 8: Algorithm Design TechniquesFour solutions to the maximum subarray problem, from cubic to Kadane's linear scan, and the story behind them.
- PracticeMaximum SubarrayKadane's problem as an exercise.
- PracticeMinimum Size Subarray SumThe variable sliding window on positive numbers.
- PracticeTwo Sum II: Input Array Is SortedThe two-pointer search.
- PracticeSubarray Sum Equals KPrefix sums with a hash map.