题目
LeetCode 2134. 最少交换次数来组合所有的 1 II(median)
交换 定义为选中一个数组中的两个 互不相同 的位置并交换二者的值。
环形 数组是一个数组,可以认为 第一个 元素和 最后一个 元素 相邻 。
给你一个 二进制环形 数组 nums
,返回在 任意位置 将数组中的所有 1
聚集在一起需要的最少交换次数。
示例 1:
输入:nums = [0,1,0,1,1,0,0]
输出:1
解释:这里列出一些能够将所有 1 聚集在一起的方案:
[0,0,1,1,1,0,0] 交换 1 次。
[0,1,1,1,0,0,0] 交换 1 次。
[1,1,0,0,0,0,1] 交换 2 次(利用数组的环形特性)。
无法在交换 0 次的情况下将数组中的所有 1 聚集在一起。
因此,需要的最少交换次数为 1 。
示例 2:
输入:nums = [0,1,1,1,0,0,1,1,0]
输出:2
解释:这里列出一些能够将所有 1 聚集在一起的方案:
[1,1,1,0,0,0,0,1,1] 交换 2 次(利用数组的环形特性)。
[1,1,1,1,1,0,0,0,0] 交换 2 次。
无法在交换 0 次或 1 次的情况下将数组中的所有 1 聚集在一起。
因此,需要的最少交换次数为 2 。
示例 3:
输入:nums = [1,1,0,0,1]
输出:0
解释:得益于数组的环形特性,所有的 1 已经聚集在一起。
因此,需要的最少交换次数为 0 。
提示:
-
1 <= nums.length <= 105
-
nums[i]
为0
或者1
解题思路
- 先统计出1的数目
len
,则最终所有1聚集在一起时,长度为len
- 遍历所有长度为
len
的区间,统计其中1的数目now_sum
,其中0的位置都需要被替换为1,则需要的操作次数为len - now_sum
- 记录遍历过程中操作次数最小值
ret
,即为最终答案
Tips:
-
由于数组是首尾相接的,因此滑动窗口可以横跨首尾,通过
(i + len - 1) % m
来得到最后一位 -
区间和即代表1的个数,可以随着滑动窗口的移动更新,即减去
nums[i - 1]
和加上nums[(i + len - 1) % m]
图示
代码(C++实现)
class Solution {
public:
int minSwaps(vector<int>& nums) {
int n = nums.size();
int len = accumulate(nums.begin(), nums.end(), 0);
if (len == n || !len) //若全为1或全为0,则不需要操作
return 0;
int now_sum = accumulate(nums.begin(), nums.begin() + len, 0);
int ret = len - now_sum;
for (int i = 1; i < n; ++i) {
now_sum -= nums[i - 1];
now_sum += nums[(i + len - 1) % n];
ret = min(ret, len - now_sum);
}
return ret;
}
};
有收获的话,求个赞~ Click Here
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-swaps-to-group-all-1s-together-ii