Facebook Pixel

1493. Longest Subarray of 1's After Deleting One Element

Problem Description

You are given a binary array nums (containing only 0s and 1s). You must delete exactly one element from this array.

After deleting one element, you need to find the longest subarray that contains only 1s. Return the length of this longest subarray. If no such subarray exists after deletion, return 0.

For example:

  • If nums = [1,1,0,1], after deleting the element at index 2 (the 0), we get [1,1,1], which gives us a subarray of length 3 containing only 1s.
  • If nums = [0,1,1,1,0,1,1,0,1], we could delete the element at index 4 (the 0), which would connect the 1s on both sides, giving us [1,1,1,1,1] as the longest subarray of 1s with length 5.
  • If nums = [1,1,1], we must still delete one element. After deleting any 1, we're left with a subarray of length 2 containing only 1s.

The key insight is that deleting an element can potentially connect two groups of consecutive 1s if we delete a 0 between them, or it will simply reduce the length of a group of 1s if we delete a 1.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key observation is that when we delete an element at position i, we're essentially trying to connect the consecutive 1s that appear before position i with the consecutive 1s that appear after position i.

Think about what happens when we delete different types of elements:

  • If we delete a 0, we can potentially join two groups of 1s that were separated by this 0
  • If we delete a 1, we break a sequence of 1s, but we still get the remaining 1s on either side

For any position i that we choose to delete, the resulting length of consecutive 1s would be:

  • The number of consecutive 1s ending right before position i
  • Plus the number of consecutive 1s starting right after position i

This leads us to think about preprocessing the array. If we can know for each position:

  1. How many consecutive 1s end at or before this position (let's call this left[i])
  2. How many consecutive 1s start at or after this position (let's call this right[i])

Then for each deletion position i, we can quickly calculate the result as left[i] + right[i+1].

The preprocessing approach makes sense because:

  • left[i] can be computed by scanning from left to right: if nums[i] is 1, then left[i] = left[i-1] + 1, otherwise it's 0
  • right[i] can be computed by scanning from right to left: if nums[i] is 1, then right[i] = right[i+1] + 1, otherwise it's 0

By trying all possible deletion positions and taking the maximum, we get our answer. This transforms a potentially complex problem into a simple enumeration with preprocessing.

Learn more about Dynamic Programming and Sliding Window patterns.

Solution Approach

The solution uses a preprocessing approach with two auxiliary arrays to efficiently calculate the result for each possible deletion position.

Step 1: Initialize auxiliary arrays

We create two arrays left and right, both of size n+1 (where n is the length of nums). These arrays are initialized with zeros:

  • left[i] will store the count of consecutive 1s ending at position i-1 in the original array
  • right[i] will store the count of consecutive 1s starting at position i in the original array

Step 2: Build the left array

We iterate through nums from left to right (using 1-based indexing for left):

for i, x in enumerate(nums, 1):
    if x:
        left[i] = left[i - 1] + 1
  • If nums[i-1] is 1, then left[i] = left[i-1] + 1 (extending the consecutive 1s)
  • If nums[i-1] is 0, then left[i] remains 0 (breaking the sequence)

Step 3: Build the right array

We iterate through nums from right to left:

for i in range(n - 1, -1, -1):
    if nums[i]:
        right[i] = right[i + 1] + 1
  • If nums[i] is 1, then right[i] = right[i+1] + 1 (extending the consecutive 1s from the right)
  • If nums[i] is 0, then right[i] remains 0

Step 4: Calculate the maximum

For each position i that we could delete (from 0 to n-1), we calculate:

  • left[i]: consecutive 1s ending just before position i
  • right[i+1]: consecutive 1s starting just after position i
  • The sum left[i] + right[i+1] gives us the length of consecutive 1s after deleting element at position i

We return the maximum value among all possible deletion positions:

return max(left[i] + right[i + 1] for i in range(n))

Time Complexity: O(n) - We make three passes through the array Space Complexity: O(n) - We use two auxiliary arrays of size n+1

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with nums = [1,1,0,1,0,1,1].

Step 1: Initialize arrays

  • n = 7
  • left = [0,0,0,0,0,0,0,0] (size 8)
  • right = [0,0,0,0,0,0,0,0] (size 8)

Step 2: Build the left array

Processing from left to right:

  • Index 0: nums[0] = 1, so left[1] = left[0] + 1 = 0 + 1 = 1
  • Index 1: nums[1] = 1, so left[2] = left[1] + 1 = 1 + 1 = 2
  • Index 2: nums[2] = 0, so left[3] = 0 (sequence breaks)
  • Index 3: nums[3] = 1, so left[4] = left[3] + 1 = 0 + 1 = 1
  • Index 4: nums[4] = 0, so left[5] = 0 (sequence breaks)
  • Index 5: nums[5] = 1, so left[6] = left[5] + 1 = 0 + 1 = 1
  • Index 6: nums[6] = 1, so left[7] = left[6] + 1 = 1 + 1 = 2

Result: left = [0,1,2,0,1,0,1,2]

Step 3: Build the right array

Processing from right to left:

  • Index 6: nums[6] = 1, so right[6] = right[7] + 1 = 0 + 1 = 1
  • Index 5: nums[5] = 1, so right[5] = right[6] + 1 = 1 + 1 = 2
  • Index 4: nums[4] = 0, so right[4] = 0 (sequence breaks)
  • Index 3: nums[3] = 1, so right[3] = right[4] + 1 = 0 + 1 = 1
  • Index 2: nums[2] = 0, so right[2] = 0 (sequence breaks)
  • Index 1: nums[1] = 1, so right[1] = right[2] + 1 = 0 + 1 = 1
  • Index 0: nums[0] = 1, so right[0] = right[1] + 1 = 1 + 1 = 2

Result: right = [2,1,0,1,0,2,1,0]

Step 4: Calculate maximum for each deletion position

For each index i, calculate left[i] + right[i+1]:

  • Delete index 0: left[0] + right[1] = 0 + 1 = 1
  • Delete index 1: left[1] + right[2] = 1 + 0 = 1
  • Delete index 2: left[2] + right[3] = 2 + 1 = 3 ✓ (connects two 1s with one 1)
  • Delete index 3: left[3] + right[4] = 0 + 0 = 0
  • Delete index 4: left[4] + right[5] = 1 + 2 = 3 ✓ (connects one 1 with two 1s)
  • Delete index 5: left[5] + right[6] = 0 + 1 = 1
  • Delete index 6: left[6] + right[7] = 1 + 0 = 1

Maximum value: 3

This makes sense! When we delete either the 0 at index 2 or the 0 at index 4, we can connect groups of 1s to get a maximum length of 3.

Solution Implementation

1class Solution:
2    def longestSubarray(self, nums: List[int]) -> int:
3        """
4        Find the longest subarray of 1s after deleting exactly one element.
5      
6        Args:
7            nums: List of binary integers (0s and 1s)
8          
9        Returns:
10            Length of the longest subarray containing only 1s after deleting one element
11        """
12        n = len(nums)
13      
14        # left[i] stores the count of consecutive 1s ending at position i-1
15        left = [0] * (n + 1)
16      
17        # right[i] stores the count of consecutive 1s starting from position i
18        right = [0] * (n + 1)
19      
20        # Build left array: count consecutive 1s from left to right
21        for i, num in enumerate(nums, 1):
22            if num == 1:
23                left[i] = left[i - 1] + 1
24            else:
25                left[i] = 0
26      
27        # Build right array: count consecutive 1s from right to left
28        for i in range(n - 1, -1, -1):
29            if nums[i] == 1:
30                right[i] = right[i + 1] + 1
31            else:
32                right[i] = 0
33      
34        # Find maximum length by trying to delete each element
35        # For each position i, combine consecutive 1s before i and after i
36        max_length = 0
37        for i in range(n):
38            max_length = max(max_length, left[i] + right[i + 1])
39      
40        return max_length
41
1class Solution {
2    public int longestSubarray(int[] nums) {
3        int n = nums.length;
4      
5        // left[i] stores the count of consecutive 1s ending at index i-1
6        int[] left = new int[n + 1];
7      
8        // right[i] stores the count of consecutive 1s starting at index i
9        int[] right = new int[n + 1];
10      
11        // Build the left array: count consecutive 1s from left to right
12        for (int i = 1; i <= n; ++i) {
13            if (nums[i - 1] == 1) {
14                left[i] = left[i - 1] + 1;
15            }
16        }
17      
18        // Build the right array: count consecutive 1s from right to left
19        for (int i = n - 1; i >= 0; --i) {
20            if (nums[i] == 1) {
21                right[i] = right[i + 1] + 1;
22            }
23        }
24      
25        // Find the maximum length by trying to remove each element
26        // and joining the consecutive 1s on both sides
27        int maxLength = 0;
28        for (int i = 0; i < n; ++i) {
29            // For each position, calculate the sum of consecutive 1s
30            // before position i and after position i
31            maxLength = Math.max(maxLength, left[i] + right[i + 1]);
32        }
33      
34        return maxLength;
35    }
36}
37
1class Solution {
2public:
3    int longestSubarray(vector<int>& nums) {
4        int arraySize = nums.size();
5      
6        // leftOnes[i] stores the count of consecutive 1s ending at position i-1
7        vector<int> leftOnes(arraySize + 1, 0);
8      
9        // rightOnes[i] stores the count of consecutive 1s starting at position i
10        vector<int> rightOnes(arraySize + 1, 0);
11      
12        // Build the leftOnes array
13        // For each position, if it's a 1, extend the consecutive count from the left
14        for (int i = 1; i <= arraySize; ++i) {
15            if (nums[i - 1] == 1) {
16                leftOnes[i] = leftOnes[i - 1] + 1;
17            }
18        }
19      
20        // Build the rightOnes array
21        // For each position from right to left, if it's a 1, extend the consecutive count from the right
22        for (int i = arraySize - 1; i >= 0; --i) {
23            if (nums[i] == 1) {
24                rightOnes[i] = rightOnes[i + 1] + 1;
25            }
26        }
27      
28        // Find the maximum length by trying to delete each element
29        // When we delete element at position i, we can connect:
30        // - consecutive 1s ending before position i (leftOnes[i])
31        // - consecutive 1s starting after position i (rightOnes[i + 1])
32        int maxLength = 0;
33        for (int i = 0; i < arraySize; ++i) {
34            int currentLength = leftOnes[i] + rightOnes[i + 1];
35            maxLength = max(maxLength, currentLength);
36        }
37      
38        return maxLength;
39    }
40};
41
1/**
2 * Finds the longest subarray of 1s after deleting one element from the array
3 * @param nums - Binary array containing only 0s and 1s
4 * @returns The length of the longest subarray containing only 1s after deleting exactly one element
5 */
6function longestSubarray(nums: number[]): number {
7    const arrayLength: number = nums.length;
8  
9    // Array to store count of consecutive 1s ending at each position (from left)
10    const consecutiveOnesFromLeft: number[] = Array(arrayLength + 1).fill(0);
11  
12    // Array to store count of consecutive 1s starting at each position (from right)
13    const consecutiveOnesFromRight: number[] = Array(arrayLength + 1).fill(0);
14  
15    // Calculate consecutive 1s from left to right
16    for (let i = 1; i <= arrayLength; ++i) {
17        if (nums[i - 1] === 1) {
18            // If current element is 1, extend the consecutive count
19            consecutiveOnesFromLeft[i] = consecutiveOnesFromLeft[i - 1] + 1;
20        }
21    }
22  
23    // Calculate consecutive 1s from right to left
24    for (let i = arrayLength - 1; i >= 0; --i) {
25        if (nums[i] === 1) {
26            // If current element is 1, extend the consecutive count
27            consecutiveOnesFromRight[i] = consecutiveOnesFromRight[i + 1] + 1;
28        }
29    }
30  
31    // Find maximum length by trying to delete each element
32    let maxLength: number = 0;
33    for (let i = 0; i < arrayLength; ++i) {
34        // For each position, combine consecutive 1s before and after deleting element at position i
35        const currentLength: number = consecutiveOnesFromLeft[i] + consecutiveOnesFromRight[i + 1];
36        maxLength = Math.max(maxLength, currentLength);
37    }
38  
39    return maxLength;
40}
41

Time and Space Complexity

Time Complexity: O(n)

The algorithm consists of three main parts:

  • First loop: Iterates through the array once to populate the left array, taking O(n) time
  • Second loop: Iterates through the array once in reverse to populate the right array, taking O(n) time
  • Final computation: Iterates through all indices to find the maximum of left[i] + right[i + 1], taking O(n) time

Since these operations are sequential and not nested, the overall time complexity is O(n) + O(n) + O(n) = O(n).

Space Complexity: O(n)

The algorithm uses additional space for:

  • left array of size n + 1
  • right array of size n + 1

Both arrays store intermediate results, requiring O(n + 1) + O(n + 1) = O(n) extra space in total.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Forgetting the Mandatory Deletion Requirement

A common mistake is not handling the case where the array contains only 1s. In this scenario, we still must delete exactly one element, so the maximum length should be n-1, not n.

Incorrect approach:

# This would incorrectly return n for an array of all 1s
return max(left[i] + right[i + 1] for i in range(n))

Why it fails: For nums = [1,1,1], this would calculate:

  • Position 0: left[0] + right[1] = 0 + 2 = 2
  • Position 1: left[1] + right[2] = 1 + 1 = 2
  • Position 2: left[2] + right[3] = 2 + 0 = 2

The result is correct (2), but only by coincidence due to how the arrays are built.

2. Off-by-One Errors in Array Indexing

The solution uses 1-based indexing for the left array but 0-based for right, which can be confusing and lead to errors.

Common mistake:

# Incorrect: mixing up the indexing
for i in range(n):
    if nums[i]:
        left[i] = left[i - 1] + 1  # Wrong! This would access left[-1] when i=0

Solution: Be consistent with indexing or clearly document the offset:

# Correct: using enumerate with start=1 for clarity
for i, num in enumerate(nums, 1):
    if num == 1:
        left[i] = left[i - 1] + 1

3. Not Initializing Arrays with Correct Size

Incorrect:

left = [0] * n  # Wrong size!
right = [0] * n

This would cause an index out of bounds error when accessing right[n] or when building the left array.

Solution: Always use size n+1 for both arrays to accommodate the boundary conditions:

left = [0] * (n + 1)
right = [0] * (n + 1)

4. Alternative Sliding Window Approach Pitfall

Some might attempt a sliding window approach tracking zeros, but forget to handle the edge case where there are no zeros in the array:

Problematic sliding window:

def longestSubarray(self, nums):
    zero_count = 0
    left = 0
    max_len = 0
  
    for right in range(len(nums)):
        if nums[right] == 0:
            zero_count += 1
      
        while zero_count > 1:  # Allow at most 1 zero
            if nums[left] == 0:
                zero_count -= 1
            left += 1
      
        max_len = max(max_len, right - left + 1)
  
    return max_len - 1  # Subtract 1 for the deletion

Why it fails: For nums = [1,1,1] with no zeros, this would return 3 - 1 = 2, which is correct. However, the logic is unclear and the -1 at the end seems arbitrary. A better approach would explicitly check if any zeros exist:

# Better: explicitly handle the all-1s case
if 0 not in nums:
    return len(nums) - 1
# ... rest of sliding window logic
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which algorithm should you use to find a node that is close to the root of the tree?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More