Facebook Pixel

1151. Minimum Swaps to Group All 1's Together 🔒

Problem Description

You are given a binary array data that contains only 0s and 1s. Your task is to find the minimum number of swaps needed to group all the 1s together in the array. The 1s can be grouped at any position in the array - they don't have to be at the beginning or end.

A swap means exchanging the positions of two elements in the array. For example, if you have [1, 0, 1, 0, 1], you could swap elements to get [1, 1, 1, 0, 0] or [0, 1, 1, 1, 0] or any other configuration where all 1s are consecutive.

The key insight is that if there are k ones in the array, then after grouping them together, they will occupy exactly k consecutive positions. The solution uses a sliding window of size k to find the window that already contains the maximum number of 1s. The positions with 0s in this optimal window are the ones that need to be swapped out with 1s from outside the window.

For example:

  • Input: [1, 0, 1, 0, 1] has three 1s
  • One possible grouping: [0, 1, 1, 1, 0] requires 1 swap
  • The sliding window of size 3 finds that positions [1,2,3] already contain two 1s, so only 1 swap is needed
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The first observation is that if we have k ones in the array, they need to occupy exactly k consecutive positions after grouping. This means we're looking for the best window of size k to place all our ones.

Think about it this way: we need to choose k consecutive positions where all ones will eventually be placed. Once we pick this window, any zeros inside it need to be swapped out with ones from outside the window. So the number of swaps equals the number of zeros in our chosen window.

To minimize swaps, we want to minimize the number of zeros in our chosen window. This is equivalent to maximizing the number of ones already present in the window. If a window already contains t ones, then it has k - t zeros, and we'll need exactly k - t swaps to fill this window with all ones.

This leads us to the sliding window approach: we slide a window of size k across the entire array and track which window position already contains the most ones. If the maximum number of ones in any window is mx, then the minimum number of swaps needed is k - mx.

For example, with array [1, 0, 1, 0, 1, 0, 0] where k = 3:

  • Window at positions [0,1,2]: contains 2 ones, needs 1 swap
  • Window at positions [1,2,3]: contains 1 one, needs 2 swaps
  • Window at positions [2,3,4]: contains 2 ones, needs 1 swap
  • And so on...

The best window has 2 ones already, so we only need 3 - 2 = 1 swap.

Learn more about Sliding Window patterns.

Solution Approach

The implementation uses a sliding window technique to efficiently find the window with the maximum number of ones.

Step 1: Count total ones

k = data.count(1)

First, we count the total number of ones in the array. This gives us the window size k that we need to consider.

Step 2: Initialize the first window

mx = t = sum(data[:k])

We calculate the number of ones in the first window of size k (positions 0 to k-1). This sum is stored in both t (current window sum) and mx (maximum ones seen so far).

Step 3: Slide the window

for i in range(k, len(data)):
    t += data[i]
    t -= data[i - k]
    mx = max(mx, t)

We slide the window one position at a time from left to right:

  • Add the new element entering the window: t += data[i]
  • Remove the element leaving the window: t -= data[i - k]
  • Update the maximum if current window has more ones: mx = max(mx, t)

This sliding technique is efficient because instead of recounting all elements in each window (which would take O(k) time per window), we only update based on the elements entering and leaving the window (O(1) time per window).

Step 4: Calculate minimum swaps

return k - mx

Since mx represents the maximum number of ones already present in any window of size k, we need to swap k - mx zeros with ones from outside to fill the window completely.

Time Complexity: O(n) where n is the length of the array - we traverse the array once.

Space Complexity: O(1) - we only use a few variables regardless of input size.

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

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

Step 1: Count total ones

  • Count all 1s in the array: [1, 0, 1, 0, 1, 0, 0]
  • Total ones k = 3
  • This means we need a window of size 3 to group all 1s together

Step 2: Initialize the first window

  • First window covers positions [0, 1, 2]: [1, 0, 1]
  • Count of 1s in this window: t = 1 + 0 + 1 = 2
  • Set mx = 2 (maximum ones seen so far)

Step 3: Slide the window

Slide 1: Move window to positions [1, 2, 3]: [0, 1, 0]

  • Add element at position 3: t += data[3] = 2 + 0 = 2
  • Remove element at position 0: t -= data[0] = 2 - 1 = 1
  • Current window has 1 one
  • Update mx = max(2, 1) = 2

Slide 2: Move window to positions [2, 3, 4]: [1, 0, 1]

  • Add element at position 4: t += data[4] = 1 + 1 = 2
  • Remove element at position 1: t -= data[1] = 2 - 0 = 2
  • Current window has 2 ones
  • Update mx = max(2, 2) = 2

Slide 3: Move window to positions [3, 4, 5]: [0, 1, 0]

  • Add element at position 5: t += data[5] = 2 + 0 = 2
  • Remove element at position 2: t -= data[2] = 2 - 1 = 1
  • Current window has 1 one
  • Update mx = max(2, 1) = 2

Slide 4: Move window to positions [4, 5, 6]: [1, 0, 0]

  • Add element at position 6: t += data[6] = 1 + 0 = 1
  • Remove element at position 3: t -= data[3] = 1 - 0 = 1
  • Current window has 1 one
  • Update mx = max(2, 1) = 2

Step 4: Calculate minimum swaps

  • Maximum ones in any window: mx = 2
  • Total ones needed: k = 3
  • Minimum swaps required: k - mx = 3 - 2 = 1

Result: We need only 1 swap to group all 1s together. The optimal windows (positions [0,1,2] or [2,3,4]) already contain 2 ones, so we just need to swap 1 zero with a 1 from outside.

Solution Implementation

1class Solution:
2    def minSwaps(self, data: List[int]) -> int:
3        # Count total number of 1s in the array
4        total_ones = data.count(1)
5      
6        # Initialize sliding window of size equal to total number of 1s
7        # Calculate sum of first window (number of 1s in first window)
8        max_ones_in_window = current_ones = sum(data[:total_ones])
9      
10        # Slide the window through the rest of the array
11        for i in range(total_ones, len(data)):
12            # Add the new element entering the window
13            current_ones += data[i]
14            # Remove the element leaving the window
15            current_ones -= data[i - total_ones]
16            # Track maximum number of 1s found in any window
17            max_ones_in_window = max(max_ones_in_window, current_ones)
18      
19        # Minimum swaps needed = total 1s - maximum 1s already in a window
20        # This represents how many 0s need to be swapped out
21        return total_ones - max_ones_in_window
22
1class Solution {
2    public int minSwaps(int[] data) {
3        // Count total number of 1s in the array
4        int totalOnes = 0;
5        for (int value : data) {
6            totalOnes += value;
7        }
8      
9        // Count number of 1s in the first window of size totalOnes
10        int onesInWindow = 0;
11        for (int i = 0; i < totalOnes; ++i) {
12            onesInWindow += data[i];
13        }
14      
15        // Track maximum number of 1s found in any window
16        int maxOnesInWindow = onesInWindow;
17      
18        // Slide the window through the rest of the array
19        for (int i = totalOnes; i < data.length; ++i) {
20            // Add new element entering the window
21            onesInWindow += data[i];
22            // Remove element leaving the window
23            onesInWindow -= data[i - totalOnes];
24            // Update maximum if current window has more 1s
25            maxOnesInWindow = Math.max(maxOnesInWindow, onesInWindow);
26        }
27      
28        // Minimum swaps needed = total 1s - maximum 1s already in a window
29        return totalOnes - maxOnesInWindow;
30    }
31}
32
1class Solution {
2public:
3    int minSwaps(vector<int>& data) {
4        // Count total number of 1s in the array
5        int totalOnes = 0;
6        for (int& value : data) {
7            totalOnes += value;
8        }
9      
10        // Count number of 1s in the first window of size totalOnes
11        int onesInWindow = 0;
12        for (int i = 0; i < totalOnes; ++i) {
13            onesInWindow += data[i];
14        }
15      
16        // Track maximum number of 1s found in any window
17        int maxOnesInWindow = onesInWindow;
18      
19        // Slide the window through the rest of the array
20        for (int i = totalOnes; i < data.size(); ++i) {
21            // Add new element entering the window
22            onesInWindow += data[i];
23            // Remove element leaving the window
24            onesInWindow -= data[i - totalOnes];
25            // Update maximum ones found in any window
26            maxOnesInWindow = max(maxOnesInWindow, onesInWindow);
27        }
28      
29        // Minimum swaps = total 1s - maximum 1s already in a window
30        return totalOnes - maxOnesInWindow;
31    }
32};
33
1/**
2 * Calculates the minimum number of swaps required to group all 1s together in the array
3 * @param data - Binary array containing only 0s and 1s
4 * @returns The minimum number of swaps needed
5 */
6function minSwaps(data: number[]): number {
7    // Count total number of 1s in the array (this will be our window size)
8    const totalOnes: number = data.reduce((sum: number, value: number) => sum + value, 0);
9  
10    // Calculate the sum of the first window (first k elements)
11    let currentWindowSum: number = data.slice(0, totalOnes).reduce((sum: number, value: number) => sum + value, 0);
12  
13    // Track the maximum number of 1s found in any window of size k
14    let maxOnesInWindow: number = currentWindowSum;
15  
16    // Slide the window through the array to find the window with maximum 1s
17    for (let i: number = totalOnes; i < data.length; i++) {
18        // Update window sum by adding new element and removing the leftmost element
19        currentWindowSum += data[i] - data[i - totalOnes];
20      
21        // Update the maximum if current window has more 1s
22        maxOnesInWindow = Math.max(maxOnesInWindow, currentWindowSum);
23    }
24  
25    // Minimum swaps = total 1s - maximum 1s already grouped together
26    return totalOnes - maxOnesInWindow;
27}
28

Time and Space Complexity

The time complexity is O(n), where n is the length of the array. The algorithm performs a single pass to count all 1s using data.count(1) which takes O(n) time, then calculates the initial sum of the first k elements in O(k) time, and finally uses a sliding window approach to iterate through the remaining elements from index k to n-1, performing constant-time operations for each element. Since k ≤ n, the overall time complexity is O(n) + O(k) + O(n-k) = O(n).

The space complexity is O(1). The algorithm only uses a fixed number of variables (k, mx, t, and loop variable i) regardless of the input size, requiring constant extra space.

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

Common Pitfalls

1. Edge Case: Empty Array or No Ones

A common pitfall is not handling the case where the array is empty or contains no 1s at all. When total_ones = 0, the code sum(data[:total_ones]) would sum an empty slice (which returns 0), but the subsequent loop wouldn't execute, and we'd return 0 - 0 = 0, which is correct. However, it's better to explicitly handle this for clarity and to avoid unnecessary computation.

Solution:

def minSwaps(self, data: List[int]) -> int:
    total_ones = data.count(1)
  
    # Handle edge cases explicitly
    if total_ones <= 1:
        return 0  # No swaps needed if 0 or 1 ones
  
    # Continue with sliding window logic...

2. Off-by-One Error in Window Sliding

Developers might incorrectly calculate the element to remove from the window. Using data[i - total_ones + 1] instead of data[i - total_ones] would remove the wrong element, leading to incorrect window sums.

Incorrect:

current_ones -= data[i - total_ones + 1]  # Wrong index!

Correct:

current_ones -= data[i - total_ones]  # Removes the first element of previous window

3. Forgetting to Update Maximum

Some implementations might forget to compare and update the maximum after each window slide, instead only checking at the end or using the wrong comparison.

Incorrect:

for i in range(total_ones, len(data)):
    current_ones += data[i] - data[i - total_ones]
    # Forgot to update max_ones_in_window!

Correct:

for i in range(total_ones, len(data)):
    current_ones += data[i] - data[i - total_ones]
    max_ones_in_window = max(max_ones_in_window, current_ones)

4. Misunderstanding the Problem

A critical pitfall is misunderstanding what needs to be minimized. Some might think we need to minimize the total number of operations or find the minimum swaps to move all 1s to the beginning/end specifically, rather than grouping them at any position.

Solution: Remember that the 1s can be grouped anywhere in the array, and we're looking for the position that requires the minimum number of swaps, which is why we check all possible windows of size total_ones.

Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

In a binary min heap, the maximum element can be found in:


Recommended Readings

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

Load More