力扣 2134. 最少交换次数来组合所有的 1 II
2134. 最少交换次数来组合所有的 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 。
提示:
1 <= nums.length <= 105
nums[i] 为 0 或者 1
思路
我主要是学习 up主 灵茶山艾府 请大家多多支持这位宝藏up主。
理解
设 nums 中有 k 个 1。
按照题目的要求,我们需要在nums数组中找到 长度为k 全为1 的子数组。
- 对于长度为k的子数组中,1不变
- 0我们与子数组之外的1交换
这样0越多,交换的次数越多。所以问题就变成了:
- 环形数组 nums 中的长为 k 的子数组中的 0 的个数的最小值。
方法
环形数组:
1.[0, k - 1]是第一个窗口
2.[n - 1, n + k - 2]是最后一个窗口
因为它是环形数组,窗口的大小呢是k,所以当窗口左断点到最后一个元素的时候,n + k - 2就是窗口的右端点。下一个窗口是[n, n + k − 1]和[0, k - 1]是一样的
3.如果下标 ≥n,我们可以将其模 n,映射到闭区间 [0, n − 1] 中
4.统计 1 的个数比统计 0 的个数方便,所以我们可以先计算出窗口中的 1 的个数的最大值,然后用 k 减去最大值,就是 0 的个数的最小值。
代码
class Solution {
public:
int minSwaps(vector<int>& nums) {
int k = reduce(nums.begin(), nums.end(), 0); // 1 的个数
if (k == 0) { // 没有 1,无需交换
return 0;
}
int n = nums.size();
int max1 = 0, cnt1 = 0;
for (int i = 0; i < n + k - 1; i++) {
// 1. 进入窗口
cnt1 += nums[i % n];
if (i < k - 1) { // 窗口大小不足 k
continue;
}
// 2. 更新答案
max1 = max(max1, cnt1);
// 3. 离开窗口,为下一个循环做准备
cnt1 -= nums[i - k + 1]; // 由于我们保证 i < n+k-1,所以 i-k+1 < n,无需取模
}
return k - max1;
}
};
本文来自博客园,作者:杰西卡若,转载请注明原文链接:https://www.cnblogs.com/jiexiekaruo/p/19064024

浙公网安备 33010602011771号