Algorithm

Maximum Sum Subarray of Size K

Sliding Window Pattern

Maximum Sum Subarray of Size K

Given an integer array nums and an integer k, look at every contiguous block of exactly k elements, and return the largest sum any such block can have. The array may contain negative numbers, so the answer itself can be negative. A valid block always exists because k is at most the array length.

CONSTRAINTS
  • 1 <= k <= nums.length <= 10⁵
  • nums contains integers (positive and negative both allowed)
  • Return the maximum window sum, not the subarray itself
EXAMPLE 1
Input: nums = [2,1,5,1,3,2], k = 3
Output: 9
The size-3 blocks are [2,1,5]=8, [1,5,1]=7, [5,1,3]=9, [1,3,2]=6. The largest is 9, from [5,1,3].
EXAMPLE 2
Input: nums = [2,3,4,1,5], k = 2
Output: 7
The size-2 blocks are [2,3]=5, [3,4]=7, [4,1]=5, [1,5]=6. The largest is 7, from [3,4].
EXAMPLE 3
Input: nums = [-1,-2,-3,-4], k = 2
Output: -3
Every block is negative: [-1,-2]=-3, [-2,-3]=-5, [-3,-4]=-7. The largest is the least negative, -3. A correct answer must be allowed to be negative.
Can the array contain negative numbers?
Yes, any integers including negatives. The maximum sum can itself be negative when every element is negative, so don't seed your answer with 0.
What if k equals the array length?
Then there is only one possible block — the whole array — and its sum is the answer.
Is k guaranteed to be valid?
Yes. The constraints promise 1 <= k <= nums.length, so at least one window always exists.
Do I return the subarray or just the sum?
Just the maximum sum value — not its indices or the elements themselves.

Read the problem slowly. You have a frame that is exactly k numbers wide. You slide it across the array, one position at a time, and among all the spots the frame can sit, you want the one where the numbers under it add up to the most. The frame never grows or shrinks — it is always k wide. That fixed width turns out to be the whole story.

Start the obvious way, then count what it costs

The first idea anyone has: go to every possible starting spot, add up the k numbers sitting there, and keep the biggest total you have seen.

python
def brute_force(nums, k):
    best = float('-inf')
    for i in range(len(nums) - k + 1):
        window_sum = sum(nums[i:i+k])   # re-adds k numbers, every single time
        best = max(best, window_sum)
    return best

There are about N starting spots, and at each one we add up k numbers, so the work is roughly N × k additions. If N and k are both large — say 100,000 each — that is billions of steps. Something is being wasted. Look closely at what sum(nums[i:i+k]) does on two turns in a row.

The waste, seen plainly

Put two neighbouring frames side by side on [2, 1, 5, 1, 3, 2] with k = 3:

- the first frame covers [2, 1, 5]
- the next frame covers [1, 5, 1]

They share the 1 and the 5. And that is not a coincidence — any two side-by-side frames overlap in all but two numbers. When the frame steps right by one, the leftmost number drops out, exactly one new number joins on the right, and everything in between is untouched. The brute force ignores that and re-adds the shared middle from scratch every time.

Reuse the overlap instead of rebuilding it

Once you know the sum of one frame, you can get the next frame's sum with two tiny fixes: subtract the number that just left on the left, add the number that just arrived on the right. However big k is, moving the frame one step now costs one subtraction and one addition — a fixed, tiny amount of work.

The Insightkeep one running total for the frame you are on; when the frame slides, patch that total by removing the outgoing number and adding the incoming one. Never re-add the shared middle.
python
def max_sum_subarray(nums, k):
    window_sum = sum(nums[:k])   # build the FIRST frame once, in full
    best = window_sum
    for i in range(k, len(nums)):
        window_sum += nums[i] - nums[i - k]   # + incoming, - outgoing
        best = max(best, window_sum)
    return best
Crucial Notethe first frame is the only one we add up the slow way — those k additions happen once, before the loop starts. After that, each move is constant work. Notice the outgoing index is i - k, not i - 1: when the incoming number sits at i, the number falling off the far left of a k-wide frame is exactly k steps behind it.
Worked Example:nums = [2, 1, 5, 1, 3, 2], k = 3
- First frame [2, 1, 5] = 8. best = 8.
- Slide: add 1, drop 2. 8 + 1 − 2 = 7. Frame [1, 5, 1]. best stays 8.
- Slide: add 3, drop 1. 7 + 3 − 1 = 9. Frame [5, 1, 3]. best = 9.
- Slide: add 2, drop 5. 9 + 2 − 5 = 6. Frame [1, 3, 2]. best stays 9.
- Answer: 9.

Now a case that catches lazy code — all negatives, nums = [-1, -2, -3, -4], k = 2. First frame [-1, -2] = −3, so best = −3. Slide: add −3, drop −1, giving −3 + (−3 − (−1)) = −5, frame [-2, -3], best stays −3. Slide again: add −4, drop −2, giving −5 + (−4 − (−2)) = −7, best still −3. Answer −3. This is exactly why best is seeded with the first frame's real sum (or −∞) and never with 0 — a 0 start would beat every negative frame and hand back a sum that no real window has.

The pattern, and how to spot it next time

That trick — carry one small summary of a fixed-width frame and patch it one-in, one-out as it glides — is the Fixed Sliding Window. It is the base shape for a whole family of problems, so it is worth pinning down exactly why it works.

Two conditions make it legal:
1. the frame's width is fixed and known up front (here it is k);
2. the thing you track about the frame can be repaired in O(1) when one element enters and one leaves. A running sum qualifies: add the newcomer, subtract the leaver, done.

The invariant you protect: at every step, window_sum equals the sum of exactly the k elements currently under the frame — never more, never fewer. You keep it true by always pairing one add with one matching remove. Break that pairing and the total quietly stops meaning anything.

The reusable skeleton, with the slots that change per problem:

build the state for the first window (indices 0 .. k-1)
record its answer
for each new right edge i from k to n-1:
    fold nums[i] into the state       # incoming
    fold nums[i-k] out of the state   # outgoing
    record / update the answer from the state

Solving a new fixed-window problem is just filling four slots: (a) the width, (b) what "state" you keep, (c) how to fold one element in and out of it, (d) what you record. Here: width k, state a running sum, fold is +/−, record is the max so far. The next two problems keep this exact skeleton and only swap the state.

Signals that should make you reach for it in an unseen question:
- the words "contiguous", "subarray", or "substring" together with a fixed, given size — "of size k", "exactly k long", "every window of length L";
- you want the best / whether-any / a count of something over all those equal-size blocks;
- N is large (10⁵ or more), so an O(N·k) re-scan is too slow and a single linear pass is clearly the intended answer.

And where it stops working, so you don't force it: if the size is not fixed — "the longest subarray whose sum stays under S" — the frame must grow and shrink, and you need the variable sliding window that comes next (Longest Substring Without Repeating Characters). Even with a fixed size, if the tracked quantity cannot be repaired in O(1) — the maximum inside the frame is the classic case, because when the current max slides out you have no idea what the next-biggest is — the plain rolling trick fails and you need extra machinery like a monotonic deque (that is Sliding Window Maximum). The frame idea survives in both; only the bookkeeping gets heavier.

Interactive Strategy Visualization

Maximum Sum Subarray

k=3
O(N) Complexity
2
0
1
1
5
2
ENTER
1
3
3
4
2
5
Current Sum
8
Best Sum Found
8
O(N × K) Brute Force
O(N) Fixed Sliding Window