[LeetCode] 2134. Minimum Swaps to Group All 1s Together II
A swap is defined as taking two distinct positions in an array and swapping the values in them.
A circular array is defined as an array where we consider the first element and the last element to be adjacent.
Given a binary circular array nums, return the minimum number of swaps required to group all 1's present in the array together at any location.
Example 1:
Input: nums = [0,1,0,1,1,0,0]
Output: 1
Explanation: Here are a few of the ways to group all the 1's together:
[0,0,1,1,1,0,0] using 1 swap.
[0,1,1,1,0,0,0] using 1 swap.
[1,1,0,0,0,0,1] using 2 swaps (using the circular property of the array).
There is no way to group all 1's together with 0 swaps.
Thus, the minimum number of swaps required is 1.
Example 2:
Input: nums = [0,1,1,1,0,0,1,1,0]
Output: 2
Explanation: Here are a few of the ways to group all the 1's together:
[1,1,1,0,0,0,0,1,1] using 2 swaps (using the circular property of the array).
[1,1,1,1,1,0,0,0,0] using 2 swaps.
There is no way to group all 1's together with 0 or 1 swaps.
Thus, the minimum number of swaps required is 2.
Example 3:
Input: nums = [1,1,0,0,1]
Output: 0
Explanation: All the 1's are already grouped together due to the circular property of the array.
Thus, the minimum number of swaps required is 0.
Constraints:
1 <= nums.length <= 105
nums[i] is either 0 or 1.
最少交换次数来组合所有的 1 II。
交换 定义为选中一个数组中的两个 互不相同 的位置并交换二者的值。 环形 数组是一个数组,可以认为 第一个 元素和 最后一个 元素 相邻 。 给你一个 二进制环形 数组 nums ,返回在 任意位置 将数组中的所有 1 聚集在一起需要的最少交换次数。
思路一
这道题跟版本一 1151 题很像,唯一不同的地方是题目多了一个条件,给的 input 是环形数组。环形数组中找连续的 1 的个数稍微有些复杂,因为最优解有可能是断开的(一部分 1 在数组起点,一部分 1 在数组终点),但是我们可以换一种思路。因为 input 数组中只有 0 和 1 两种数字,那么我们可以试着比较把所有的 1 聚集在一起的开销少还是把所有的 0 聚集在一起的开销少。
复杂度
时间O(n)
空间O(1)
代码
Java实现
class Solution {
public int minSwaps(int[] nums) {
int n = nums.length;
int ones = 0;
int zeros = 0;
for (int num : nums) {
if (num == 0) {
zeros++;
}
}
ones = n - zeros;
int a = helper(nums, 0, zeros);
int b = helper(nums, 1, ones);
return Math.min(a, b);
}
private int helper(int[] nums, int target, int p) {
int start = 0;
int end = 0;
int count = 0;
int res = Integer.MAX_VALUE;
while (end < nums.length) {
if (nums[end] == target) {
count++;
}
end++;
if (end - start == p) {
res = Math.min(res, p - count);
if (nums[start] == target) {
count--;
}
start++;
}
}
return res;
}
}
思路二
固定 size 的滑动窗口。对于一个长度为 n 的数组而言,因为 1 有可能分布在数组的两端,所以我们可以通过扫描一个 2n 的长度来确保扫描到所有的 1。记得要对下标取模。
复杂度
时间O(n)
空间O(1)
代码
Java实现
class Solution {
public int minSwaps(int[] nums) {
int n = nums.length;
int k = 0;
for (int num : nums) {
if (num == 1) {
k++;
}
}
int count = 0;
// first k
for (int i = 0; i < k; i++) {
if (nums[i] == 1) {
count++;
}
}
int swap = k - count;
for (int i = k; i < 2 * n; i++) {
if (nums[i % n] == 1) {
count++;
}
if (nums[(i - k) % n] == 1) {
count--;
}
swap = Math.min(swap, k - count);
}
return swap;
}
}
// sliding window with fixed size
相关题目
1151. Minimum Swaps to Group All 1s Together
2134. Minimum Swaps to Group All 1s Together II