本文涉及的基础知识点
C++算法:滑动窗口及双指针总结
LeetCode2134. 最少交换次数来组合所有的 1 II
交换 定义为选中一个数组中的两个 互不相同 的位置并交换二者的值。
环形 数组是一个数组,可以认为 第一个 元素和 最后一个 元素 相邻 。
给你一个 二进制环形 数组 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 。
滑动窗口
n = nums.length
cnt1是所有1的数量。
我们枚举[i,i+cnt1-1]交换完成后,全部是1。需求的交换次数是:cnt1 - 此子数组1的数量。
[i1+1,i1+cnt1]相比 [i1,i1+cnt1-1],多了nums[(i1+cnt1)%n] 少了nums[i1]。
代码
核心代码
class Solution {
public:
int minSwaps(vector<int>& nums) {
int cnt1 = count(nums.begin(), nums.end(), 1);
int cnt = count(nums.begin(), nums.begin() + cnt1, 1);
int ans = cnt;
for (int i = 1 ; i < nums.size(); i++) {
cnt += (nums[(i+cnt1-1)%nums.size()] == 1);
cnt -= (nums[i -1] == 1);
ans = max(ans, cnt);
}
return cnt1 - ans;
}
};
单元测试
vector<int> nums;
TEST_METHOD(TestMethod11)
{
nums = { 0,1,0,1,1,0,0 };
auto res = Solution().minSwaps(nums);
AssertEx(1, res);
}
TEST_METHOD(TestMethod12)
{
nums = { 0,1,1,1,0,0,1,1,0 };
auto res = Solution().minSwaps(nums);
AssertEx(2, res);
}
TEST_METHOD(TestMethod13)
{
nums = { 1,1,0,0,1 };
auto res = Solution().minSwaps(nums);
AssertEx(0, res);
}