DSA sheet · Arrays · Sliding Window pattern (fixed size)

Maximum Subarray with Sum K

This is the first question of the sliding window pattern in the sheet (on GFG it's called "Max Sum Subarray of size K"). The teacher uses it to introduce what a sliding window is. She first writes the natural two-loop brute force, works out the loop limits carefully, shows from the constraints why it gives TLE, rules out the other array patterns one by one, and then turns it into the fixed-size sliding window: "add the next number, subtract the leftmost".

Why it matters: this "add one, remove one" move is the heart of every fixed-size window problem (anagrams, sliding window maximum, permutation in string). Get this one perfectly and the rest are small changes.

Every part below follows the same order:
① the question in simple words → ② what the constraints tell us → ③ intuition → ④ building the logic from examples → ⑤ approach steps → ⑥ code → ⑦ code line by line → ⑧ dry run → ⑨ complexity & remember

Part 0 · Before starting

Subarray = window

A subarray is a piece of the array whose elements sit next to each other (contiguous): pick a start and an end, take everything between, skip nothing. In sliding-window language, a subarray is called a window, and we describe it as [left..right] (both ends included). Its length is right − left + 1.

index01234
arr1421023[1..3] = [4, 2, 10] is a window of size 3

The brute-force problem: repeated work

To look at every window we can use two loops: a start pointer, and an end pointer that walks forward and adds things up. There are about n²/2 windows (or n − k + 1 windows of a fixed size k, each costing k additions). Neighbouring windows share almost all their cells, but the brute force adds those shared cells again every time. Sliding window fixes exactly this.

Expand and shrink

Both pointers only move forward, so in total they make at most 2n moves.

Fixed-size vs variable-size windows

FIXED size (this problem)VARIABLE size (problems 3, 4, 6, 7, 11, 12, 14)
sizealways k, given in the questionchanges; the best size is the answer
left movesexactly one step with every right steponly when a condition says so (zero or many steps)
loop shapebuild first k cells, then add arr[right], remove arr[right − k]add arr[right], then while the window is bad (or good, for shortest), remove arr[left]
negatives?fine: it never makes decisions, it just visits every windowbreak sum problems: adding a negative lowers the sum, so "grow = bigger" stops being true

Other shapes you'll meet later in this notebook: longest valid (record after shrinking), shortest valid (record while shrinking), count of valid windows (count += right − left + 1, because every start from left to right gives a valid window ending at right), and "exactly K = atMost(K) − atMost(K − 1)". Problem 1 (the overview) covers them all.

The 4 array patterns the teacher always checks

patternwhen it works
Two pointersOnly the two end values matter, not what's between them.
Sliding windowContiguous range where everything inside matters, normal sums of different subarrays, no negatives (for variable windows).
Prefix sumContiguous sums where you must answer many range queries ("sum from index 3 to 6? from 7 to 10?").
Kadane's algorithmContiguous sums with negative numbers, looking for the max sum.

Part A · Brute force: two loops over every window

GFG "Max Sum Subarray of size K"

1The question in simple words

You get an array of integers arr and a number k. Look at every subarray of length exactly k, add up each one, and return the largest total.

The teacher's example, with k = 4:

index012345678
arr142102331020k = 4 → answer 39

All windows of size 4:

startwindowsum
01, 4, 2, 1017
14, 2, 10, 2339 (max)
22, 10, 23, 338
310, 23, 3, 137
423, 3, 1, 027
53, 1, 0, 2024

Can a window start at index 6 (value 1)? No: from there only 3 elements are left (1, 0, 20), not 4. So the last possible start is index 5.

2What the constraints tell us

3Intuition: list every window and add it up

The first thing that comes to mind: for every start position i, take the k numbers from i onwards, add them up, and keep the biggest total. Two loops: the outer one picks the start, the inner one adds k numbers.

4Building the loop limits from the example (the part she does slowly)

Where must the outer loop stop?

The indexes go 0 … 8, so n = 9. The last start that still has k = 4 numbers is index 5. And 5 = 9 − 4 = n − k. So the outer loop runs i from 0 up to and including n − k.

Doubt 1: in her Java loop she says "run till n − k". Is it i < n − k or i <= n − k?
→ It must include n − k, because index 5 is a real window (3, 1, 0, 20). With i < n − k the last window is skipped, and if the max were in that window you'd get a wrong answer. In Python: for i in range(n - k + 1). (This doesn't change her example's answer, 39, but my tests include a case where the last window is the biggest.)

Where must the inner loop stop? (her j < k slip)

For every i we want exactly 4 numbers starting from i (not from i + 1). So j starts at i. She first tries j < k:

The fix: stop at i + k, not k. Then i = 0 gives 0..3, i = 1 gives 1..4, i = 2 gives 2..5. Always 4 numbers ✓.

Doubt 2: why does j < k look right at first?
→ Because the first test case is i = 0, and then i + k equals k. The bug only shows from i = 1 on. Her tip: always check a loop limit on the second iteration too, not just the first.

Adding up and keeping the max

Doubt 3: what should best start at?
→ In the brute force, every window is compared, including the first one. Since all numbers are ≥ 1 (positive), any window sum is bigger than 0, so starting at 0 (or even −1) is safe here. (In Part B she changes this, and explains why.)

5Approach steps

  1. best = 0, n = len(arr).
  2. For each start i from 0 to n − k (inclusive): set total = 0.
  3. For j from i to i + k − 1: total += arr[j].
  4. best = max(best, total).
  5. Return best.

6Code (Python)

Brute force: every window of size k, O(n·k)
class Solution:
    def maxSubarraySum(self, arr, k):
        n = len(arr)
        best = 0                         # safe: all numbers are positive
        for i in range(n - k + 1):       # last start is n - k (included)
            total = 0                    # fresh sum for this window
            for j in range(i, i + k):    # exactly k numbers from i
                total += arr[j]
            best = max(best, total)
        return best

7Code line by line

linewhat it means
best = 0The answer so far. 0 is fine because every real window sum is positive.
for i in range(n - k + 1):Every start that still has k numbers after it: 0, 1, …, n − k.
total = 0Reset for the new window, so the previous window's sum doesn't leak in.
for j in range(i, i + k):The k positions i, i+1, …, i+k−1. Her fix: the limit is i + k, not k.
total += arr[j]Add one number of this window.
best = max(best, total)After the window is complete, keep the larger of the old best and this sum.

8Dry run (hand table)

arr = [1, 4, 2, 10, 23, 3, 1, 0, 20], k = 4, n = 9 → i goes 0..5.

ij runstotal growswindow sumbest after
00..31 → 5 → 7 → 171717
11..44 → 6 → 16 → 393939
22..52 → 12 → 35 → 383839
33..610 → 33 → 36 → 373739
44..723 → 26 → 27 → 272739
55..83 → 4 → 4 → 242439

(On screen she first calls the third window 37, then corrects it to 38. 2 + 10 + 23 + 3 = 38.)

Answer: 39 ✓. Notice the work: windows 0 and 1 share 4, 2, 10, and we added those three numbers twice.

9Complexity & remember

Remember the brute forceOuter i from 0 to n − k inclusive; inner j from i to i + k (not k); reset total per window. O(n·k) → TLE at n = 10⁶.

Part B · Optimal: fixed-size sliding window

1The question again, with the new goal

Same question. The goal now is O(n): each element should be touched a constant number of times, not k times.

2What the constraints tell us now: choosing the pattern

Whenever she optimises an array problem, she goes through her four patterns and rules them out one by one:

Doubt: wouldn't prefix sum also work? Each window sum is P[i + k] − P[i].
→ Yes, that's also O(n) and correct. But it needs an extra array of n + 1 numbers (O(n) space). The sliding window gets the same O(n) time with O(1) space, so it's the better answer here. (This comparison is my addition.)

3Intuition: don't recount the middle

Look at the first two windows only, as if the array were just [1, 4, 2, 10, 23]:

window 11421023sum 17
window 2142102317 + 23 − 1 = 39

The brute force runs the inner loop 4 times (indexes 0–3), then 4 more times (1–4). That's 8 additions for only 5 elements. The numbers 4, 2, 10 are added twice.

Window 2 is just window 1 with 23 added on the right and 1 removed from the left. So: compute the first window once; after that, every next window = previous sum + the new right number − the old left number. One add and one subtract is O(1), so the inner k-loop disappears. O(n·k) becomes O(n).

4Building the code from the example

Step 1: the first window

We can't slide until we have something to slide. So run a loop k times to get the first window's sum: window_sum = 1 + 4 + 2 + 10 = 17.

Step 2: where does the sliding loop start?

The first number to add is 23, at index 4. And 4 = k. So the second loop is j from k to n − 1.

Step 3: which index leaves? (her hint)

When j = 4 joins, index 0 must leave. How do we get 0 from j = 4? Subtract k: 4 − 4 = 0. Next, when j = 5 (value 3) joins, 5 − 4 = 1 leaves (value 4). It always works: the cell that leaves is j − k.

Doubt 1: why exactly j − k?
→ Before the step, the window is [j − k .. j − 1] (k cells ending just before j). After adding j, the window would have k + 1 cells, [j − k .. j]. Dropping the first one, j − k, leaves [j − k + 1 .. j], exactly k cells again.

Step 4: how do we start best? (0 vs the first window)

She changes her mind here, on purpose. The sliding loop only compares the windows from the second one on. If best starts at 0, the first window is never compared. Her example: if the first window's sum were 50 (the biggest), starting at 0 would lose it. So start best with the first window's sum, "to be on the safe side".

Doubt 2: but in the brute force 0 was fine. What changed?
→ In the brute force, the max update is inside the loop that visits every window, including the first. In the sliding version, the first window is built in a separate loop with no max update. If best = 0 there and the first window is the largest, the answer comes out wrong (e.g. [50, 1, 1], k = 1 → 1 instead of 50). My tests include this case.

5Approach steps

  1. window_sum = 0. For i in 0..k−1: window_sum += arr[i]. (first window)
  2. best = window_sum.
  3. For j from k to n − 1: window_sum += arr[j] (new number joins), window_sum -= arr[j − k] (leftmost leaves).
  4. best = max(best, window_sum).
  5. Return best.

6Code (Python)

Optimal: fixed-size sliding window, O(n)
class Solution:
    def maxSubarraySum(self, arr, k):
        n = len(arr)
        window_sum = 0
        for i in range(k):               # first window: indexes 0..k-1
            window_sum += arr[i]
        best = window_sum                # the first window counts too
        for j in range(k, n):            # j = the number that joins
            window_sum += arr[j]         # add the new right number
            window_sum -= arr[j - k]     # remove the old left number
            best = max(best, window_sum)
        return best

7Code line by line

linewhat it means
for i in range(k): window_sum += arr[i]Build the first window the normal way, once. Costs k steps.
best = window_sumThe first window is a candidate. Starting at 0 would skip it.
for j in range(k, n):j is the index of the number that joins. The first one to join is index k.
window_sum += arr[j]Expand: the new right end joins.
window_sum -= arr[j - k]Shrink: the cell k places back leaves, so the size stays k.
best = max(best, window_sum)Every slide gives a new complete window, so compare every time.
return bestThe largest window sum.

8Dry run (hand table)

arr = [1, 4, 2, 10, 23, 3, 1, 0, 20], k = 4.

stepright j (value added)window beforesum after addingshrink? (what leaves, why)window afterbest
build0..3—17no, just building k cells[0..3]17
14 (23)[0..3]40yes: index 0 (1) leaves, size must stay 4 → 39[1..4]39
25 (3)[1..4]42index 1 (4) leaves → 38[2..5]39
36 (1)[2..5]39index 2 (2) leaves → 37[3..6]39
47 (0)[3..6]37index 3 (10) leaves → 27[4..7]39
58 (20)[4..7]47index 4 (23) leaves → 24[5..8]39
build142102331020sum 17
L  R     
step 1142102331020+23 −1 = 39 (best)
 L  R    
step 5142102331020+20 −23 = 24, last window
     L  R

Answer: 39 ✓, the same as the brute force, with 4 + 5 = 9 steps instead of 6 × 4 = 24 additions.

9Complexity & remember

Her Java submission was accepted, and this is the most optimised version.

Remember the optimalBuild the first k → best = window_sum → for j from k: +arr[j], −arr[j − k], update best. Both ends move together; the size never changes.

Part C · Revision page

Brute forceSliding window
ideafor every start, add k numbersfirst window once, then +new −old
loopsnested: i to n − k, j from i to i + ktwo separate loops: 0..k−1, then k..n−1
start of best0 (all positive)the first window's sum
time / spaceO(n·k) / O(1)O(n) / O(1)
n = 10⁶, k = 10³≈ 10⁹ → TLE≈ 10⁶ → fast
patternwhy it does / doesn't fit
Two pointersonly the two end values matter there; here everything inside matters
Kadane'sfor negatives; here all numbers ≥ 1
Prefix sumfor many range queries (works, but costs O(n) extra space)
Sliding window (fixed)sums of consecutive windows of one fixed size
If you remember only 5 lines 1. Fixed size k → fixed sliding window.
2. Last start = n − k (included); a window from i is i..i+k−1.
3. Next sum = previous sum + arr[j] − arr[j − k].
4. Start best with the first window, not 0.
5. k + (n − k) = n steps → O(n), O(1) space.
Mistakes to avoid ✗ outer loop i < n − k (misses the last window)
✗ inner loop j < k instead of j < i + k
✗ not resetting the sum for each start in the brute force
✗ subtracting arr[j − k + 1] or arr[j − 1] instead of arr[j − k]
✗ best = 0 in the sliding version (loses the first window)
test it yourself (paste under either Solution above)
s = Solution()
print(s.maxSubarraySum([1, 4, 2, 10, 23, 3, 1, 0, 20], 4))   # 39
print(s.maxSubarraySum([100, 200, 300, 400], 2))             # 700
print(s.maxSubarraySum([50, 1, 1], 1))                       # 50 (first window is the max)
print(s.maxSubarraySum([1, 1, 9], 2))                        # 10 (last window is the max)
print(s.maxSubarraySum([5, 5, 5], 3))                        # 15 (k = n)

Based on this video: Maximum Sum Subarray of Size K | Sliding Window