Longest Subarray of 1s After Deleting One Element [Medium] — Sliding Window

Sanjeev SharmaSanjeev Sharma
13 min read

Advertisement

Problem Statement

Given a binary array nums, you must delete exactly one element from the array. Return the length of the longest non-empty subarray consisting entirely of 1s in the resulting array.

Examples:

Input:  nums = [1, 1, 0, 1]
Output: 3
Explanation: Delete the 0 at index 2. The result is [1,1,1], length 3.
 
Input:  nums = [0, 1, 1, 1, 0, 1, 1, 0, 1]
Output: 5
Explanation: Delete the 0 at index 4. The result is [0,1,1,1,1,1,0,1], and the
             longest subarray of 1s is [1,1,1,1,1], length 5.
 
Input:  nums = [1, 1, 1]
Output: 2
Explanation: You must delete one element. Delete any 1. Result is [1,1], length 2.

Constraints:

  • 1 <= nums.length <= 100,000
  • nums[i] is either 0 or 1


Why This Problem Matters

This problem is essentially LC 1004 — Max Consecutive Ones III with k = 1, but with one critical twist: you must delete exactly one element, not at most one. That "must" changes the edge case for an all-ones array — instead of returning the full array length, you return length - 1 because you are forced to delete something.

Why do interviewers love this problem?

  1. It tests whether you really understand sliding window, not just memorised it. Candidates who blindly copy the "at most k zeros" template miss the off-by-one in the return statement.
  2. It probes edge-case awareness. What happens when the input has no zeros at all? What about a single element? These edge cases are free interview points if you mention them upfront.
  3. It bridges to harder problems. Understanding why the answer is window_size - 1 (not window_size) is the mental model that unlocks LC 487, LC 1004, and entire families of "flip at most k bits" problems.

Companies that have asked this or a direct variant in interviews include Amazon, Google, Meta, and Microsoft. It often appears as a warm-up before a harder two-pointer or binary search question.


The Sliding Window Insight

Let us build the intuition from first principles.

Step 1 — Reformulate the problem.

Deleting one element from a binary array is the same as "skipping over" one position. If we want the longest subarray of all 1s after deleting one element, we are really asking:

What is the longest contiguous window in the original array that contains at most one 0? Subtract 1 (for the deleted element slot) and that is your answer.

Step 2 — Why subtract 1?

When our window [left, right] contains exactly one 0, that 0 is the element we "delete." The resulting subarray of 1s has length right - left + 1 - 1 = right - left. When the window contains zero 0s (all 1s), we still must delete one 1, giving length right - left + 1 - 1 = right - left.

In both cases the answer is right - left — the window size minus 1. This is the single formula that handles every case, including the all-ones edge case.

Step 3 — Variable sliding window mechanics.

We maintain two pointers left and right and a counter zeros tracking how many 0s are inside the current window:

  • Expand right one step at a time. If nums[right] == 0, increment zeros.
  • If zeros > 1, shrink from the left: if nums[left] == 0, decrement zeros, then advance left.
  • At every step, candidate answer = right - left.

The window never needs to shrink below size 1 because the problem guarantees the input is non-empty and we always delete exactly one element.


Visual Dry Run

Let us trace through nums = [0, 1, 1, 1, 0, 1, 1, 0, 1] step by step.

We track: left, right, zeros, and candidate = right - left.

Index:  0  1  2  3  4  5  6  7  8
nums:   0  1  1  1  0  1  1  0  1
Steprightnums[right]zerosleftWindow indicescandidate
10010[0..0]0
21110[0..1]1
32110[0..2]2
43110[0..3]3
54020too many zerosshrink...
nums[0]=0, zeros=1, left=1
5b411[1..4]3
65111[1..5]4
76111[1..6]5 ← max
87021too many zerosshrink...
nums[1]=1, zeros=2, left=2
nums[2]=1, zeros=2, left=3
nums[3]=1, zeros=2, left=4
nums[4]=0, zeros=1, left=5
8b715[5..7]2
98115[5..8]3

Final answer: 5 (window [1..6] = [1,1,1,0,1,1], delete the 0 at index 4, giving five 1s).

Key observations from the trace:

  • The window [1..6] spans indices 1 through 6 (six elements). Subtract the one 0 inside it = 5.
  • The formula right - left = 6 - 1 = 5 captures this without us explicitly counting 1s.
  • When we had to shrink (step 8), we moved left all the way from 1 to 5 because we needed to evict the 0 at index 4.

Common Mistakes

Mistake 1 — Returning right - left + 1 instead of right - left.

This is the most common bug. If your window is [left..right] with one 0, the window has right - left + 1 elements total. After deleting the 0, you have right - left ones. The + 1 is consumed by the mandatory deletion. Candidates who write right - left + 1 will fail on the all-ones case: [1,1,1] would return 3, but the correct answer is 2.

Mistake 2 — Not handling the all-ones input.

Input [1, 1, 1] has no zeros. Some candidates think "no zero to delete, return 3." But the problem says you must delete exactly one element. The answer is 2. The right - left formula handles this automatically — the max window spans the whole array with zeros = 0, so right - left = 2 - 0 = 2. If you add a special case to handle "no zeros found, return n," you introduce a bug.

Mistake 3 — Shrinking with a while loop but decrementing zeros only on left advance.

A subtle off-by-one appears when candidates write:

# Buggy version
while zeros > 1:
    zeros -= 1   # Wrong: should only decrement if nums[left] == 0
    left += 1

This decrements zeros even when nums[left] is 1, corrupting the count. Always guard: if nums[left] == 0: zeros -= 1 before left += 1.

Mistake 4 — Initialising ans as 0 and forgetting to update inside the loop.

If you compute ans only after the loop ends, you capture the final window, not the maximum window seen. Always update ans = max(ans, right - left) inside the loop at every step.

Mistake 5 — Confusing this with "at most k zeros, return window size."

LC 1004 returns right - left + 1 because you do not have to delete anything — you flip zeros to ones. LC 1493 returns right - left because you must delete. Mixing these up costs you the problem in an interview.


Solutions

Python

def longestSubarray(nums: list[int]) -> int:
    left = 0          # left boundary of the sliding window
    zeros = 0         # number of 0s inside the current window [left..right]
    ans = 0           # best answer seen so far
 
    for right in range(len(nums)):
        # Expand window: include nums[right]
        if nums[right] == 0:
            zeros += 1          # one more zero entered the window
 
        # Shrink window from the left until we have at most one 0
        while zeros > 1:
            if nums[left] == 0:
                zeros -= 1      # a zero is leaving the window from the left
            left += 1           # advance left boundary
 
        # Window [left..right] has at most one 0.
        # We must delete exactly one element (the 0, or any 1 if zeros==0).
        # Either way the surviving subarray of 1s has length = right - left.
        ans = max(ans, right - left)
 
    return ans

Why right - left and not right - left + 1?

The window [left, right] contains right - left + 1 elements. One of them will be deleted (either the 0 if zeros == 1, or a forced 1 if zeros == 0). After deletion: right - left + 1 - 1 = right - left.


JavaScript

/**
 * @param {number[]} nums
 * @return {number}
 */
var longestSubarray = function(nums) {
    let left = 0;   // left pointer of the sliding window
    let zeros = 0;  // count of 0s inside the window [left..right]
    let ans = 0;    // maximum subarray length of 1s found so far
 
    for (let right = 0; right < nums.length; right++) {
        // Expand: bring nums[right] into the window
        if (nums[right] === 0) {
            zeros++;            // a zero just entered from the right
        }
 
        // Shrink from the left until the window has at most one 0
        while (zeros > 1) {
            if (nums[left] === 0) {
                zeros--;        // a zero is leaving from the left
            }
            left++;             // move left boundary inward
        }
 
        // Window [left..right] is valid (at most one 0).
        // Subtract 1 for the mandatory deletion — answer is window size minus 1.
        ans = Math.max(ans, right - left);
    }
 
    return ans;
};

Complexity Analysis

MetricValueExplanation
TimeO(n)Each element enters and leaves the window at most once. Both right and left only move forward.
SpaceO(1)Only three integer variables: left, zeros, ans. No auxiliary data structures.

The two-pointer sliding window is optimal here — you cannot solve this faster than O(n) because you must inspect every element at least once to know if it is 0 or 1.


Follow-up Questions

Interviewers frequently extend this problem. Here are the two most common follow-ups and how the insight transfers.

Follow-up 1 — What if you can delete at most k elements? (LC 1004)

LC 1004 — Max Consecutive Ones III gives you a budget of k flips. The window condition becomes zeros &lt;= k instead of zeros &lt;= 1. The return value changes to right - left + 1 because you do not have to delete anything — flipping a 0 to 1 keeps all elements in place.

# LC 1004 template (k flips allowed, no forced deletion)
def longestOnes(nums, k):
    left = zeros = ans = 0
    for right in range(len(nums)):
        if nums[right] == 0:
            zeros += 1
        while zeros > k:
            if nums[left] == 0:
                zeros -= 1
            left += 1
        ans = max(ans, right - left + 1)  # +1 here because nothing is deleted
    return ans

Follow-up 2 — At most two consecutive zeros? (LC 487)

LC 487 — Max Consecutive Ones II asks: flip at most one 0 to 1, return the longest subarray of 1s. This is k = 1 of LC 1004, but the return value is right - left + 1 (no forced deletion). It is the complement of LC 1493 — same window logic, different return formula.

The pattern across all three:

ProblemWindow conditionReturn
LC 1493zeros &lt;= 1, must deleteright - left
LC 487zeros &lt;= 1, may flipright - left + 1
LC 1004zeros &lt;= k, may flipright - left + 1

Recognising this family in an interview signals strong pattern mastery.


This Pattern Solves

The "variable sliding window with a budget" pattern applies wherever you have:

  • A contiguous subarray constraint (longest, shortest, count)
  • A "budget" of allowed violations (zeros, mismatches, distinct characters)
  • An expand-right / shrink-left loop that keeps violations within budget

Problems directly solved by this template:

  • LC 3 — Longest Substring Without Repeating Characters (budget = 0 repeated chars)
  • LC 424 — Longest Repeating Character Replacement (budget = k non-dominant chars)
  • LC 487 — Max Consecutive Ones II (budget = 1 zero flip)
  • LC 1004 — Max Consecutive Ones III (budget = k zero flips)
  • LC 1493 — This problem (budget = 1 zero, forced deletion)

Once you internalise the template, the only things that change per problem are the "violation condition" and whether you return right - left or right - left + 1.


Key Takeaways

  • The mandatory deletion means the window size minus 1 is the answer, not the window size — return right - left (not right - left + 1).
  • Maintain a sliding window with at most 1 zero; shrink from the left when zeros > 1.
  • This is LC 1004 (Max Consecutive Ones III with k=1) with the twist that even an all-1s array still deletes one element — handle this by noting the result is n-1 in that edge case (the window constraint handles it automatically via right - left).
  • O(n) time, O(1) space — the most efficient possible solution for this type of problem.
  • The pattern generalizes: "longest subarray with at most k violations" → sliding window with shrink on violations > k, return right - left + 1 - k (for mandatory deletions) or right - left + 1 (without).
  • Amazon, Google, and Meta use this as a warm-up hard/medium to check comfort with the sliding window template before escalating to harder variants.
  • Variation: if the problem said "at most one deletion" (optional), handle the all-1s case separately and return the full window length when zeros == 0.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading