Given a binary array data
(that is, an array consisting only of 0
s and 1
s), your task is to find the minimum number of swaps needed to group all the 1
s together in the array.
Each swap can swap any two elements (not necessarily adjacent). The goal is to make all the 1
s appear in a consecutive block, and you want to do this using as few swaps as possible.
Constraints:
1
in data
.1
(if they are already grouped).Input: data = [1,0,1,0,1]
Output: 1
At first glance, it may seem like you need to try all possible swaps between 1
s and 0
s to group the 1
s together. However, this brute-force approach would be inefficient, especially for large arrays.
Instead, notice that the minimum number of swaps is determined by how many 0
s are present in the "window" (subarray) where you want to group all the 1
s. Since you know the total number of 1
s in the array, you can try to find a subarray of that length that contains the maximum number of 1
s. The fewer 0
s in that window, the fewer swaps you need to make.
This observation leads us to consider a sliding window approach, where you slide a window of size equal to the total number of 1
s across the array and count the number of 0
s in each window. The minimum number of 0
s in any such window is the answer.
Let's break down the optimized solution step by step:
1
s are in the array. Let's call this totalOnes
.totalOnes
and slide it across the array.1
s are in it. The number of 0
s in the window is window size - number of 1's in window
.1
s found in any window of size totalOnes
.totalOnes - maxOnesInWindow
.0
s in the best window to 1
s.1
s without redundant computation.
Let's walk through the example data = [1,0,1,0,1]
:
totalOnes = 3
).totalOnes - maxOnesInWindow = 3 - 2 = 1
Brute-force Approach:
class Solution:
def minSwaps(self, data):
total_ones = sum(data)
if total_ones == 0 or total_ones == len(data):
return 0
max_ones = curr_ones = sum(data[:total_ones])
for i in range(total_ones, len(data)):
curr_ones += data[i] - data[i - total_ones]
max_ones = max(max_ones, curr_ones)
return total_ones - max_ones
class Solution {
public:
int minSwaps(vector<int>& data) {
int totalOnes = 0;
for (int num : data) totalOnes += num;
if (totalOnes == 0 || totalOnes == data.size()) return 0;
int currOnes = 0, maxOnes = 0;
for (int i = 0; i < totalOnes; ++i) currOnes += data[i];
maxOnes = currOnes;
for (int i = totalOnes; i < data.size(); ++i) {
currOnes += data[i] - data[i - totalOnes];
maxOnes = max(maxOnes, currOnes);
}
return totalOnes - maxOnes;
}
};
class Solution {
public int minSwaps(int[] data) {
int totalOnes = 0;
for (int num : data) totalOnes += num;
if (totalOnes == 0 || totalOnes == data.length) return 0;
int currOnes = 0;
for (int i = 0; i < totalOnes; i++) currOnes += data[i];
int maxOnes = currOnes;
for (int i = totalOnes; i < data.length; i++) {
currOnes += data[i] - data[i - totalOnes];
maxOnes = Math.max(maxOnes, currOnes);
}
return totalOnes - maxOnes;
}
}
var minSwaps = function(data) {
let totalOnes = data.reduce((a, b) => a + b, 0);
if (totalOnes === 0 || totalOnes === data.length) return 0;
let currOnes = 0;
for (let i = 0; i < totalOnes; i++) currOnes += data[i];
let maxOnes = currOnes;
for (let i = totalOnes; i < data.length; i++) {
currOnes += data[i] - data[i - totalOnes];
maxOnes = Math.max(maxOnes, currOnes);
}
return totalOnes - maxOnes;
};
To solve the "Minimum Swaps to Group All 1's Together" problem, we recognized that the core challenge is to find a window where the 1
s can be grouped with the least effort. By using a sliding window of size equal to the total number of 1
s and counting the number of 0
s in each window, we efficiently determine the minimum swaps needed. This approach is both elegant and efficient, reducing the problem from a potentially slow brute-force solution to a linear-time algorithm.