Skip to main content

Max Consecutive Ones III Java Solution with Sliding Window

Complete Java implementation for finding maximum consecutive ones with at most k flips, using sliding window technique with O(n) time and space complexity.

The Max Consecutive Ones III problem requires finding the maximum length of consecutive ones in a binary array when we can flip at most k zeros to ones. This classic sliding window problem demonstrates efficient array manipulation and optimal substructure thinking.

1. Problem Restatement

Clarifying questions to ask the interviewer:

  1. What is the maximum size of the input array? (e.g., is it bounded by memory constraints or expected to be very large?)
  2. Can we modify the input array in-place? (This affects space complexity and implementation strategy.)
  3. What is the expected time complexity target? (e.g., O(n) or O(n log n)?)
  4. Are there any constraints on the values in the array? (e.g., are we guaranteed only 0s and 1s?)
  5. Should the solution handle edge cases like empty arrays or arrays with all 0s or all 1s?

Restatement of the problem:

Given a binary array (containing only 0s and 1s) and an integer k, determine the maximum length of a contiguous subarray that contains at most k zeros. The goal is to find the longest contiguous sequence where we can flip at most k zeros to ones.

Clarification of inputs, outputs, and constraints:

  • Input: A binary array nums of length n (where each element is either 0 or 1) and integer k (number of zeros we can flip)
  • Output: Integer representing the maximum length of contiguous subarray with at most k zeros flipped to ones
  • Constraints:
    • nums.length can be up to 10^5 (large input size)
    • k is between 0 and nums.length
    • Array elements are only 0s and 1s
  • Assumption: We can modify the input array if needed (this affects space complexity trade-offs)

Data shape and hidden structure:

The problem involves a sliding window over a binary array where we're trying to maximize the window size under a constraint (at most k zeros). The key insight is that we're looking for the longest contiguous subarray where flipping at most k zeros gives us a sequence of all 1s. This suggests a sliding window pattern where we maintain a window with at most k zeros and expand it greedily while tracking the maximum size.

The problem has a hidden structure in that we're essentially finding the optimal "window" where we can make at most k flips to get all 1s in that window. The optimal solution will involve a sliding window approach where we expand the right boundary and contract the left when we exceed k zeros.

2. Pattern Recognition

Identifying the most likely pattern or patterns

The most likely pattern is sliding window technique combined with two pointers.

Why this fits the sliding window pattern

The problem asks us to find the maximum length of a subarray that contains at most K zeros, which can be transformed to 1s. This is a classic sliding window problem where:

  • We want to maintain a valid window (at most K zeros)
  • We expand the window by moving the right pointer
  • We shrink the window from left when we exceed K zeros
  • We track the maximum valid window size

Key signals in the problem statement

  1. "maximum length of subarray" - This immediately suggests we're looking for an optimal contiguous segment
  2. "at most K zeros" - This creates a constraint that we can maintain with a sliding window approach
  3. "transform zeros to ones" - This tells us we're essentially looking for the longest contiguous segment that requires at most K flips

Core insight needed to solve it

The key insight is that we can use a sliding window where:

  • The window represents a valid subarray (at most K zeros)
  • We expand the window by moving the right pointer
  • When we exceed K zeros, we shrink from the left until constraint is satisfied
  • The maximum window size during this process gives us our answer

This pattern is very similar to problems like "Longest Substring with At Most K Distinct Characters" or "Max Consecutive Ones II", where we maintain a constraint while sliding through the array.

The problem is fundamentally about finding the maximum contiguous segment under a specific constraint, making sliding window the natural approach.

3. Approach Evolution

My first instinct is to use a sliding window approach because this problem asks for the maximum length of a subarray with at most K zeros that can be flipped. This is a classic sliding window pattern where we want to maintain a valid window and expand it as much as possible.

Let me think about this more carefully. If I were to use a brute force approach, I'd check every possible subarray and count the zeros in each one. That would be O(n³) - O(n²) subarrays, and for each I'd need O(n) to count zeros. That's definitely not optimal.

I can do better by using a sliding window with two pointers. The key insight is that I want to maintain a window where the number of zeros is at most K. When I encounter more than K zeros, I shrink the window from the left until it becomes valid again.

Let me trace through this approach:

  • I'll use two pointers: left and right to define my window
  • I'll keep a count of zeros in the current window
  • When zero count exceeds K, I move left pointer until it's valid again
  • I track the maximum window size throughout this process

This approach maintains the invariant that at any point, the current window contains at most K zeros. The time complexity becomes O(n) since each element is visited at most twice - once by right pointer, once by left pointer.

The core insight is that this is a variable-size sliding window problem where the constraint is "at most K zeros". This is a common pattern that can be solved efficiently with two pointers.

The key optimization here is avoiding redundant counting by maintaining a running count and using the sliding window technique to expand and contract the window efficiently.

4. Data Structure Choice

For this problem, I'll use a sliding window approach with two pointers and a queue to track zero positions.

Primary Data Structures Used:

  1. Array/Integer[]: The input array is our primary data structure to iterate through and find the maximum consecutive ones with up to K flips.

  2. Two Pointers (left, right): These form our sliding window that expands and contracts to find the optimal subarray.

  3. Queue: Used to track indices of zeros in our current window. This helps us efficiently find the leftmost zero when we need to shrink the window.

Why Each Data Structure Is Needed:

  • Array: The input array is fundamental to the problem - we must iterate through it to find consecutive ones and determine where flips are needed.

  • Two Pointers: The sliding window technique requires maintaining a window [left, right] that represents the current subarray we're analyzing. The left pointer marks the start of our window, and the right pointer expands it.

  • Queue: While we could use a simple counter to track zeros, a queue makes it easy to efficiently remove the leftmost zero when we must shrink our window. This is key for O(n) time complexity.

Time and Space Impact:

  • Time Complexity:

    • Array iteration: O(n)
    • Queue operations (add/remove): O(1) amortized
    • Overall: O(n)
  • Space Complexity:

    • Queue can hold at most K+1 elements (in worst case where all zeros in window are flipped)
    • Array is input and not counted in space complexity
    • Overall: O(K) where K is the number of allowed flips

Helper Structure for Simplicity:

The queue serves as a helper structure to simplify the logic of tracking which zero to "remove" when our window exceeds K flips. Without it, we'd need to manually search for the leftmost zero in our window each time we shrink, which would increase complexity.

This approach elegantly handles the constraint that we can flip at most K zeros, making it easy to maintain the invariant that our window contains at most K zeros.

5. Algorithm Walkthrough

Let me trace through the algorithm with a concrete example to demonstrate how it works step-by-step.

Example: nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2

Step-by-step execution:

  1. Initialization:

    • left = 0, right = 0, maxOnes = 0, zeros = 0
    • Window: [1] (size 1)
  2. Expand window:

    • right = 0: nums[0] = 1 → no zero, window becomes [1]
    • right = 1: nums[1] = 1 → no zero, window becomes [1,1]
    • right = 2: nums[2] = 1 → no zero, window becomes [1,1,1]
    • right = 3: nums[3] = 0 → zero found, zeros = 1, window becomes [1,1,1,0]
  3. Continue expanding:

    • right = 4: nums[4] = 0 → zero found, zeros = 2, window becomes [1,1,1,0,0]
    • right = 5: nums[5] = 0 → zero found, zeros = 3, window becomes [1,1,1,0,0,0]
    • Critical point: zeros > k (3 > 2), so we must shrink window
  4. Shrink window:

    • left = 0: nums[0] = 1 → not zero, window becomes [1,1,1,0,0,0]
    • left = 1: nums[1] = 1 → not zero, window becomes [1,1,0,0,0]
    • left = 2: nums[2] = 1 → not zero, window becomes [1,0,0,0]
    • left = 3: nums[3] = 0 → zero found, zeros = 2, window becomes [0,0,0]
  5. Continue expanding:

    • right = 6: nums[6] = 1 → no zero, window becomes [0,0,0,1]
    • right = 7: nums[7] = 1 → no zero, window becomes [0,0,0,1,1]
    • right = 8: nums[8] = 1 → no zero, window becomes [0,0,0,1,1,1]
    • right = 9: nums[9] = 1 → no zero, window becomes [0,0,0,1,1,1,1]
    • right = 10: nums[10] = 0 → zero found, zeros = 3, window becomes [0,0,0,1,1,1,1,0]
  6. Shrink again:

    • left = 4: nums[4] = 0 → zero found, zeros = 2, window becomes [0,0,1,1,1,1,0]
  7. Final window:

    • right = 10, left = 4 → window size = 7

Key moments in execution:

  • The algorithm maintains a sliding window that can contain at most k zeros
  • When we exceed k zeros, we shrink from the left until we're back under the limit
  • At each valid window, we track the maximum size seen so far

Edge case handling:

  • When k = 0, we just find the longest consecutive ones without flipping any
  • When all elements are 1s, zeros never exceeds k, so we get the full array length
  • When all elements are 0s, we can flip at most k zeros to get window size k

The algorithm terminates correctly because:

  1. We process each element at most twice (once as right pointer, once as left pointer)
  2. The window invariant ensures we never have more than k zeros in our current window
  3. We always track the maximum valid window size encountered

6. Java Solution

public class MaxConsecutiveOnesIII {
    public int longestOnes(int[] nums, int k) {
        int left = 0;
        int maxLen = 0;
        int zerosCount = 0;
        
        // Sliding window approach
        for (int right = 0; right < nums.length; right++) {
            // Expand window by including nums[right]
            if (nums[right] == 0) {
                zerosCount++;
            }
            
            // Shrink window from left until we have at most k zeros
            while (zerosCount > k) {
                if (nums[left] == 0) {
                    zerosCount--;
                }
                left++;
            }
            
            // Update maximum length of valid window
            maxLen = Math.max(maxLen, right - left + 1);
        }
        
        return maxLen;
    }
}

This solution uses a sliding window technique to find the longest subarray with at most k zeros that can be flipped to ones. The key insight is to maintain a window where we never exceed k zeros, and whenever we do, we shrink the window from the left until the constraint is satisfied again. The algorithm efficiently tracks the maximum valid window size throughout the process.

The solution handles edge cases naturally:

  • When k is 0, we're looking for the longest subarray of all 1s
  • When k is large enough, we can flip all zeros in the array
  • Empty arrays return 0 as expected

7. Complexity Analysis

Time Complexity: O(n)

The algorithm uses a sliding window approach with two pointers that traverse the array exactly once. Each element is visited at most twice - once by the right pointer and once by the left pointer when shrinking the window. Since we perform constant-time operations at each step (checking if we need to flip, updating counters, etc.), the overall time complexity is linear.

Space Complexity: O(1)

The solution only uses a constant amount of extra space regardless of input size. We maintain a fixed number of variables (left, right, flips, maxOnes) that do not scale with the input array size. No additional data structures like hash maps, stacks, or queues are required.

Why these bounds are correct:

The linear time complexity is optimal for this problem since we must examine each element at least once to determine the maximum consecutive ones possible with at most k flips. The space complexity is optimal because we only need to track the current window state and aggregate results, without requiring any auxiliary storage that grows with input size.

This solution achieves the theoretical lower bounds for both time and space complexity, making it near-optimal for this problem. The algorithm's performance characteristics make it suitable for large input sizes where both time and memory efficiency are critical.

The solution is optimal because:

  1. We cannot solve this without examining each element at least once
  2. We only need to track a constant number of state variables
  3. The sliding window technique ensures we never revisit elements unnecessarily

8. Edge Cases & Pitfalls

Empty and Minimal Inputs

  • Empty array: Handle gracefully with nums.length == 0 check, returning 0
  • Single element arrays: Test with both 0 and 1 values to ensure correct handling of k=0 and k=1 cases
  • k=0: Should return the maximum consecutive 1s without any flips

Duplicate Values and Repeated States

  • All zeros: Algorithm should correctly return 0 when no 1s exist
  • All ones: Should return array length regardless of k value
  • Multiple consecutive sequences: Need to ensure sliding window properly handles transitions between sequences

Boundary Conditions

  • k larger than array size: When k >= nums.length, return nums.length since all elements can be flipped
  • Array size equals k: When k == nums.length, return nums.length regardless of initial values
  • k=0 with all zeros: Should return 0, not throw an exception

Common Implementation Mistakes

  • Incorrect window size tracking: Not properly maintaining the actual window size during expansion/shrinkage operations
  • Off-by-one errors in window management: Mismanaging when to increment/decrement window pointers
  • Not handling the case where k is larger than array size: Failing to account for the edge case where all elements can be flipped
  • Incorrectly updating max length: Updating result before properly validating window constraints
  • Failing to reset zero count when shrinking window: This can lead to incorrect zero counting in subsequent iterations

Implementation-specific Issues

  • Integer overflow: While not a major concern for this problem, ensure k is handled properly when it's at the boundary of integer limits
  • Array index out of bounds: Ensure proper bounds checking when accessing nums[right] and nums[left]
  • Incorrect zero counting logic: When tracking zeros in the current window, ensure we're decrementing count when removing a zero from window

9. Alternative Approaches

There are several alternative approaches to solving the Max Consecutive Ones III problem, each with different trade-offs:

1. Sliding Window with Two Pointers (Optimal) The primary approach we implemented uses a sliding window with two pointers, maintaining a window that can contain at most K zeros. This is optimal with O(n) time and O(1) space complexity.

2. Binary Search on Answer We could binary search on the length of the maximum consecutive ones. For each candidate length, we check if there exists a subarray of that length with at most K zeros. This approach would be O(n log n) time complexity but requires implementing a helper function to check each window size.

3. Prefix Sum Approach We could precompute prefix sums to quickly calculate the number of zeros in any subarray. However, this would require O(n) space for prefix sums and still need to check all possible windows, making it less efficient than our sliding window solution.

4. Brute Force with Window Validation A naive approach would check all possible windows of every size and validate if they contain at most K zeros. This would be O(n³) time complexity, which is clearly suboptimal.

The sliding window approach is preferred because it's linear in time and space, maintains the optimal invariant (at most K zeros in current window), and is intuitive to understand and implement. The alternative approaches either have higher time complexity or use more space unnecessarily.

The key insight is that we can maintain a valid window by expanding the right pointer and contracting the left pointer only when the constraint is violated, making it a clean and efficient solution.

10. Test Cases

public class MaxConsecutiveOnesIII {
    public int longestOnes(int[] nums, int k) {
        // Implementation here
    }
}
// Test cases for MaxConsecutiveOnesIII
public class MaxConsecutiveOnesIIITests {
    
    @Test
    public void testExample1() {
        // Input: nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2
        // Expected: 6
        // Explanation: Flip two 0s to get 6 consecutive 1s
        int[] nums = {1,1,1,0,0,0,1,1,1,1,0};
        int k = 2;
        assertEquals(6, new MaxConsecutiveOnesIII().longestOnes(nums, k));
    }
    
    @Test
    public void testAllOnes() {
        // Input: nums = [1,1,1], k = 0
        // Expected: 3
        int[] nums = {1,1,1};
        int k = 0;
        assertEquals(3, new MaxConsecutiveOnesIII().longestOnes(nums, k));
    }
    
    @Test
    public void testAllZeros() {
        // Input: nums = [0,0,0], k = 2
        // Expected: 3
        int[] nums = {0,0,0};
        int k = 2;
        assertEquals(3, new MaxConsecutiveOnesIII().longestOnes(nums, k));
    }
    
    @Test
    public void testSingleElement() {
        // Input: nums = [1], k = 0
        // Expected: 1
        int[] nums = {1};
        int k = 0;
        assertEquals(1, new MaxConsecutiveOnesIII().longestOnes(nums, k));
    }
    
    @Test
    public void testSingleZero() {
        // Input: nums = [0], k = 1
        // Expected: 1
        int[] nums = {0};
        int k = 1;
        assertEquals(1, new MaxConsecutiveOnesIII().longestOnes(nums, k));
    }
    
    @Test
    public void testEdgeCaseWithKZero() {
        // Input: nums = [1,0,1], k = 0
        // Expected: 1
        int[] nums = {1,0,1};
        int k = 0;
        assertEquals(1, new MaxConsecutiveOnesIII().longestOnes(nums, k));
    }
    
    @Test
    public void testMultipleZeros() {
        // Input: nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], k = 3
        // Expected: 10
        int[] nums = {0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1};
        int k = 3;
        assertEquals(10, new MaxConsecutiveOnesIII().longestOnes(nums, k));
    }
}

11. Final Summary

The core insight is to use a sliding window approach to find the longest subarray that can be made all 1s by flipping at most K 0s. By maintaining a window where we track the count of 0s and shrink it when we exceed K flips, we efficiently explore all valid windows to find the maximum length.

This solution works because it leverages the sliding window technique to avoid redundant computations - once we know a window is valid, we can expand it to find longer valid windows. The key optimization is that we never need to reprocess elements, making it linear in both time and space complexity.

The efficiency comes from the fact that we only make one pass through the array, maintaining a constant-size window and updating our maximum length as we go. This approach is optimal for this problem since we must examine each element at least once to determine the maximum possible consecutive ones.

Was this article helpful?

Topics in this article

More from DSA Problems

  • DSA Problems

    Subarrays with K Different Integers

    Learn to count subarrays containing exactly K distinct integers using sliding window technique with detailed Java implementation.

  • DSA Patterns

    Fixed-Size Sliding Window Techniques in Java

    Master fixed-size window algorithms including maximum sum subarray, longest substring with k distinct characters, and optimal sliding window patterns for FAANG interviews.

  • DSA Problems

    Move Zeroes Algorithm Solution

    Complete Java implementation for moving all zeroes to the end of an array while maintaining relative order of non-zero elements.

  • DSA Problems

    Longest Repeating Character Replacement Algorithm

    Learn to find the maximum length of a substring that can be made with at most k replacements to make all characters the same.

Stay in the Loop

Get curated DSA patterns, coding problems, frontend and backend LLD/HLD, and AI/ML System Design insights delivered straight to your inbox. No spam, just focused interview and engineering content.