交换 定义为选中一个数组中的两个 互不相同 的位置并交换二者的值。
环形 数组是一个数组,可以认为 第一个 元素和 最后一个 元素 相邻 。
给你一个 二进制环形 数组 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凑在一起还需要多少个,这就是结果。这个一团指的是窗口大小为1的总个数的窗口中所有的1。
class Solution {
public:
int minSwaps(vector<int>& nums) {
if (nums.size() <= 3){
return 0;
}
int count = 0;
for (int i = 0; i<nums.size(); i++) {
count += nums[i];
}
if (count <= 1 || nums.size() - count <=1){
return 0;
}
int min = 0,left = 0, right=0;
int max = nums[0];
int real = nums[0];
while (left < nums.size()){
int interval = right >= left ? right-left+1 : right+nums.size()-left+1;
if (interval <count){
right ++;
real += nums[right];
}
else {
left ++;
right = (right + 1) % nums.size();
real = real - nums[left-1] + nums[right];
}
if(real > max){
max = real;
}
}
return count - max;
}
};
最后看了别人写的代码,真的比我写的简洁多了。好痛苦