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

Max Consecutive Ones

The second sliding window question in the sheet, and the first one where the window has no fixed size. The teacher starts with a two-loop brute force, shows on an all-ones array how much of its work is wasted, picks the pattern by ruling the others out, and then writes a one-pass counter. While submitting she also finds a classic bug: the last run of ones is never checked if the array doesn't end in a 0, and she fixes it on screen.

Why it matters: this is the simplest variable-size, longest-window problem. Its "when the window breaks, jump the left end straight past the bad cell" idea, and its "check once more after the loop" lesson, come back in Max Consecutive Ones III and many string problems.

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 contiguous piece of an array (start, end, everything in between, nothing skipped). We call it a window and write it as [left..right], both ends included. Length = right − left + 1. "Consecutive ones" just means a window that contains only 1s.

The brute force tries every start and walks an end pointer forward: about n² steps, and windows that overlap get counted again and again. A sliding window walks right forward once, and moves left forward only when it has to. Neither pointer ever goes back, so the total work is O(n).

Fixed vs variable windows

FIXED size (problem 2)VARIABLE size (this problem)
sizegiven as kunknown: the longest run is the answer
left movesone step with every right steponly when the window breaks (here: a 0 arrives)
record answerafter every slidefor "longest": whenever the window is valid

Other shapes later in the notebook: shortest valid window (record while shrinking), count of valid windows (count += right − left + 1), and "exactly K = atMost(K) − atMost(K − 1)". Variable windows need a one-way condition: once a window is bad, growing it can't make it good again. Here that's true: once a 0 is inside, adding more cells never removes it. (For sums, the same idea fails with negative numbers.) Problem 1 covers all of these.

The 4 array patterns the teacher checks

patternwhen it works
Two pointersonly the values at two positions matter
Sliding windowcontiguous subarray, everything inside matters
Prefix sumcontiguous sums, many range queries
Kadane'scontiguous sums with negative numbers (max sum)

Part A · Brute force: a run from every start

LeetCode 485

1The question in simple words

You get a binary array nums (every value is 0 or 1). Return the length of the longest stretch of 1s in a row.

index012345
nums110111runs of 2 and 3 → answer 3

Count the first run: 2. The 0 can't be included, so after it we start counting again: 1, 2, 3. The bigger run is 3. Another LeetCode example: [1, 0, 1, 1, 0, 1] → 2.

2What the constraints tell us

3Intuition

Stand at each index i. If it's a 1, walk forward with a second pointer j while you keep seeing 1s. When j hits a 0, the run that started at i is over. Its length is the answer for this start. Do this for every i and keep the largest.

4Building the logic from her examples

Example: [1, 1, 1, 0, 1, 1, 1, 1]

  1. i = 0. j starts at i: 1 ✓, 1 ✓, 1 ✓, then index 3 is 0 → stop. j = 3.
  2. Length? Indexes 0, 1, 2 are the run, that's 3. And j − i = 3 − 0 = 3.
  3. i = 1 → j stops at 3 again → length 2. i = 2 → length 1. i = 3 is itself a 0 → j doesn't move → length 0.
  4. i = 4 → j walks 4, 5, 6, 7 and then runs off the end (j = 8) → length 4.
Doubt 1: normally length is j − i + 1. Why j − i here?
→ Because j is standing on the 0, which is not part of the run. j − i + 1 would count that 0 too, so we subtract 1 again: j − i + 1 − 1 = j − i.

Her all-ones example: where the time goes

Take [1, 1, 1, 1, 1]. From i = 0, j walks all 5 cells → length 5. From i = 1, j walks 4 cells → 4. From i = 2 → 3… Every start walks to the end. That's 5 + 4 + 3 + 2 + 1 steps, about n²/2.

And it's pointless: from i = 0 we already got the longest run (5); every later start in the same run is guaranteed to be shorter, because it stops at the same place but starts later. This waste is what Part B removes.

Her code, and a bug in it

Her brute force: for every i, a loop for j; when nums[j] == 0, compute the length j − i, update the max, and break out of the j loop.

Doubt 2 (a fix): what if j never meets a 0?
→ Then the break branch never runs and that run's length is never recorded. On [1, 1, 1, 1, 1] her version returns 0. On [1, 1, 0, 1, 1, 1] it returns 2 instead of 3. She meets exactly this bug later, in the optimal code (Part B, step 4), but the brute force has it too. Fix: record the length when the j loop ends for any reason, a 0 or the end of the array. In the code below, j walks with a while that stops at a 0 or at n, and the max is updated after it. j − i is still right in both cases, because j = n is also "one past the run".
Doubt 3: she writes the inner loop as j = 0. Should j start at 0?
→ No, j must start at i: we measure the run that starts at i. Her explanation says this clearly ("start j from the same index i"); the 0 is just a slip on screen.

5Approach steps

  1. best = 0.
  2. For each start i: put j at i.
  3. While j is inside the array and nums[j] == 1: move j forward.
  4. j is now on a 0 or at n. The run is i..j−1, length j − i. Update best.
  5. Return best.

6Code (Python)

Brute force: run from every start, O(n²)
class Solution:
    def findMaxConsecutiveOnes(self, nums):
        n = len(nums)
        best = 0
        for i in range(n):
            j = i                                # start the run at i
            while j < n and nums[j] == 1:        # stop at a 0 OR at the end
                j += 1
            best = max(best, j - i)              # j is not part of the run
        return best

7Code line by line

linewhat it means
for i in range(n):Every index gets a turn as the start of a run.
j = iThe end pointer starts at the start (not at 0).
while j < n and nums[j] == 1:Keep walking while we're on 1s. j < n comes first so we never read past the end.
best = max(best, j - i)Runs every time, whether the walk stopped at a 0 or at the end. This is the fix for her break-only version.
return bestThe longest run.

8Dry run (hand table)

nums = [1, 1, 1, 0, 1, 1, 1, 1].

ij stops atwhylength j − ibest
030 at index 333
130 at index 323
230 at index 313
33nums[3] is 0 itself03
48end of array44
58end34
68end24
78end14

Answer: 4 ✓. With the break-only version, the rows for i = 4..7 would record nothing and the answer would be 3 ✗.

9Complexity & remember

Remember the brute forceFor each i, walk j over 1s; length = j − i (j sits on the 0 or at n). Record the length even when j runs off the end.

Part B · Optimal: one pass with a running count (sliding window)

1The question again, with the new goal

Same question, but now in one pass: O(n).

2Choosing the pattern

3Intuition: don't restart inside a run

From Part A: if i = 0 runs until the 0 at index 3, then starting at i = 1 or 2 hits the same 0 and is just shorter. So the best length for this run already came from its leftmost start.

So when we hit a 0, there's no point moving the start forward one step at a time. Jump the start straight to the cell after the 0, and start a fresh run there. In window terms: the window is the current run of 1s; a 0 empties it, and left jumps to right + 1.

And since we only need the length of the current run, we don't even need a left pointer: a counter count does it. A 1 → count += 1. A 0 → the run is over: save it in the max and reset count = 0.

4Building the logic, the way she writes it

  1. Variables: max_count = 0 (the answer), count = 0 (the current run's length).
  2. She first writes a while loop with j: if nums[j] == 1, then j += 1 and count += 1. Else (a 0): update max_count = max(max_count, count), reset count = 0, and j += 1.
  3. She notices j += 1 is in both branches, so it can move out of the if/else. And a pointer that moves one step every time, no matter what, is just a for loop. So she switches to a for loop. Same logic.
Doubt 1: why reset count to 0 at a zero, and not keep it?
→ The 0 breaks the run. The next 1 starts a brand-new run that can't include anything before the 0. If you kept 3, the next run would wrongly start counting at 4.

The bug she finds while dry-running (her most important point)

Take [1, 1, 1, 0, 1, 1, 1, 1]. The first run (3) is saved when the 0 arrives. Then count goes 1, 2, 3, 4 on the last run... and the loop ends. The else branch only runs on a 0, and no 0 comes after the last run. So 4 is never compared with max_count. Returning max_count gives 3 ✗.

(She first types return count, corrects it to return max_count, and then spots this case.) The fix: compare one last time before returning: return max(max_count, count).

Doubt 2: can I just update the max on every 1 instead?
→ Yes: put max_count = max(max_count, count) right after count += 1. Then the last run is checked as it grows, and no final check is needed. It does a few more max() calls but is just as correct. Her version only updates on zeros plus once at the end. Both are O(n).
Doubt 3: where is the "window" in this code?
→ The window is the current run: [left..right] where left is the cell after the last 0. count is just right − left + 1, its length. A 0 sets left = right + 1 (an empty window). The second code block below writes the same thing with an explicit left pointer, so you can see it as a sliding window. That version is my addition.

5Approach steps

  1. max_count = 0, count = 0.
  2. For each value x in nums: if x is 1 → count += 1.
  3. Else (x is 0) → max_count = max(max_count, count), then count = 0.
  4. After the loop → return max(max_count, count) (the last run may never have been saved).

6Code (Python)

Optimal: running count, O(n)
class Solution:
    def findMaxConsecutiveOnes(self, nums):
        max_count = 0
        count = 0                                # length of the current run of 1s
        for j in range(len(nums)):
            if nums[j] == 1:
                count += 1                       # the run grows
            else:
                max_count = max(max_count, count)   # a 0 ends the run: save it
                count = 0                        # start fresh after the 0
        return max(max_count, count)             # the last run was never saved
Same idea with an explicit window [left..right]
class Solution:
    def findMaxConsecutiveOnes(self, nums):
        left = 0
        best = 0
        for right in range(len(nums)):
            if nums[right] == 0:
                left = right + 1                 # window can't hold a 0: jump past it
            else:
                best = max(best, right - left + 1)
        return best

7Code line by line

linewhat it means
max_count = 0 count = 0The best run so far, and the run we're in right now.
for j in range(len(nums)):j moves one step every time, whatever the value. That's why a for loop is enough.
if nums[j] == 1: count += 1Another 1 → the current window grows by one.
max_count = max(max_count, count)A 0 closes the run, so it's time to compare it with the best.
count = 0The window restarts after the 0 (left jumps to j + 1).
return max(max_count, count)Her fix: if the array ends with 1s, the last run is still sitting in count.
left = right + 1(window version) The 0 can't be inside, so the next possible window starts right after it.
best = max(best, right - left + 1)(window version) Updated on every 1, so no final check is needed.

8Dry run (hand table)

nums = [1, 1, 1, 0, 1, 1, 1, 1]. In her code, count = the window's length and the window is [left..right].

stepright (value added)window beforecount after addingshrink? (what leaves, why)window aftermax_count
10 (1)[0..0]1no[0..0]0
21 (1)[0..1]2no[0..1]0
32 (1)[0..2]3no[0..2]0
43 (0)[0..3]—yes: a 0 can't be inside, save 3, everything leavesempty (left = 4)3
54 (1)[4..4]1no[4..4]3
65 (1)[4..5]2no[4..5]3
76 (1)[4..6]3no[4..6]3
87 (1)[4..7]4no[4..7]3 ← not updated!
end——4——return max(3, 4) = 4
step 311101111count 3
L R     
step 4111011110 hit: save 3, left jumps to 4 (no step-by-step shrinking)
   RL   
step 811101111count 4, but no 0 follows → needs the final max()
    L  R

The LeetCode example [1, 1, 0, 1, 1, 1] has the same trap: the longest run (3) is at the end, so without the final check you'd return 2.

9Complexity & remember

Her Java submission beat about 98%.

Remember the optimal1 → count += 1. 0 → save the max, count = 0. Return max(max_count, count), because the last run has no 0 after it to trigger the save.

Part C · Revision page

Brute forceRunning count (sliding window)
ideafrom every i, walk j over the 1sone pass; a 0 closes the window, left jumps past it
lengthj − i (j is on the 0 or at n)count (= right − left + 1)
traprun that reaches the end not recordedlast run not compared → max(max_count, count)
time / spaceO(n²) / O(1)O(n) / O(1)
patternwhy it does / doesn't fit
Two pointersonly two positions matter there
Prefix sumno sum needed
Kadane'sno negatives (only 0/1)
Sliding windowlongest contiguous window of 1s
If you remember only 5 lines 1. Longest run of 1s = longest window with no 0 inside.
2. Every later start inside the same run is shorter, so never restart inside a run.
3. On a 0: save the run, reset the count (left jumps to right + 1).
4. After the loop: max(max_count, count).
5. O(n) time, O(1) space.
Mistakes to avoid ✗ forgetting the last run (array ends in 1s)
✗ return count instead of the max
✗ not resetting count after a 0
✗ starting the inner j at 0 instead of i (brute force)
✗ using j − i + 1 when j is standing on the 0
test it yourself (paste under any Solution above)
s = Solution()
print(s.findMaxConsecutiveOnes([1, 1, 0, 1, 1, 1]))         # 3
print(s.findMaxConsecutiveOnes([1, 0, 1, 1, 0, 1]))         # 2
print(s.findMaxConsecutiveOnes([1, 1, 1, 0, 1, 1, 1, 1]))   # 4 (last run is the longest)
print(s.findMaxConsecutiveOnes([1, 1, 1, 1, 1]))            # 5 (no zeros at all)
print(s.findMaxConsecutiveOnes([0, 0, 0]))                  # 0 (no ones)

Based on this video: Max Consecutive Ones | Sliding Window