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
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 EvaluatorExample 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
.
In a binary min heap, the maximum element can be found in:
Recommended Readings
https assets algo monster cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in the window The window
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!