[LeetCode] 1151. Minimum Swaps to Group All 1's Together
Given a binary array data
, return the minimum number of swaps required to group all 1
’s present in the array together in any place in the array.
Example 1:
Input: data = [1,0,1,0,1] Output: 1 Explanation: There are 3 ways to group all 1's together: [1,1,1,0,0] using 1 swap. [0,1,1,1,0] using 2 swaps. [0,0,1,1,1] using 1 swap. The minimum is 1.
Example 2:
Input: data = [0,0,0,1,0] Output: 0 Explanation: Since there is only one 1 in the array, no swaps needed.
Example 3:
Input: data = [1,0,1,0,1,0,0,1,1,0,1] Output: 3 Explanation: One possible solution that uses 3 swaps is [0,0,0,0,0,1,1,1,1,1,1].
Example 4:
Input: data = [1,0,1,0,1,0,1,1,1,0,1,0,0,1,1,1,0,0,1,1,1,0,1,0,1,1,0,0,0,1,1,1,1,0,0,1] Output: 8
Constraints:
1 <= data.length <= 105
data[i]
is0
or1
.
最少交换次数来组合所有的 1。
给出一个二进制数组 data
,你需要通过交换位置,将数组中所有的 1 组合到一起,并返回所有可能中所需最少的交换次数。
这道题问的是 swap 的次数,但是其实是需要换一个思路思考的,因为这个题你没法总结出来什么样的 swap 策略是最优的。我这里提供一个滑动窗口的思路。这道题前缀和也能做,日后有时间我再补充。注意这道题的滑动窗口尺寸是固定的。滑动窗口的尺寸就是 1 的个数。
首先我们用一个变量 ones 记录 input 数组中一共有多少个 1。然后我们用滑动窗口的模板开始扫描 input 数组,当 end 指针遇到 1 的时候,count++;当 end 和 start 两个指针的距离 == ones 的时候,此时我们看一下 end 和 start 之间有几个 1,此时 ones 和 count 的差值就是需要 swap 的次数。遍历整个数组,找到全局最小的 swap 次数即可。
时间O(n)
空间O(1)
Java实现
1 class Solution { 2 public int minSwaps(int[] data) { 3 int ones = 0; 4 for (int d : data) { 5 if (d == 1) { 6 ones++; 7 } 8 } 9 // corner case 10 if (ones == 0) { 11 return 0; 12 } 13 14 // normal case 15 int start = 0; 16 int end = 0; 17 int count = 0; 18 int res = Integer.MAX_VALUE; 19 while (end < data.length) { 20 if (data[end] == 1) { 21 count++; 22 } 23 end++; 24 if (end - start == ones) { 25 res = Math.min(res, ones - count); 26 if (data[start] == 1) { 27 count--; 28 } 29 start++; 30 } 31 } 32 return res; 33 } 34 }
这里我再提供一个 for 循环的代码。因为这道题滑动窗口的 size 是固定的,所以 for 循环也能做。
Java实现
1 class Solution { 2 public int minSwaps(int[] data) { 3 // 统计一共有多少个1 4 int ones = 0; 5 for (int d : data) { 6 if (d == 1) { 7 ones++; 8 } 9 } 10 11 // 统计前ones个位置上有多少个1 12 int c = 0; 13 for (int i = 0; i < ones; i++) { 14 if (data[i] == 1) { 15 c++; 16 } 17 } 18 // corner case 19 // 如果1都在一开始的位置上,则无需swap 20 if (c == ones) { 21 return 0; 22 } 23 24 // normal case 25 // min是一开始的位置上需要swap的次数 26 int min = ones - c; 27 int k = c; 28 for (int j = ones; j < data.length; j++) { 29 if (data[j] == 1) { 30 k++; 31 } 32 if (data[j - ones] == 1) { 33 k--; 34 } 35 min = Math.min(min, ones - k); 36 } 37 return min; 38 } 39 }