[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] is 0 or 1.

最少交换次数来组合所有的 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 }

 

LeetCode 题目总结

posted @ 2021-03-11 03:04  CNoodle  阅读(777)  评论(0编辑  收藏  举报