目标
给你一个二进制数组 nums 。
你可以对数组执行以下操作 任意 次(也可以 0 次):
- 选择数组中 任意 一个下标 i ,并将从下标 i 开始一直到数组末尾 所有 元素 反转 。
反转 一个元素指的是将它的值从 0 变 1 ,或者从 1 变 0 。
请你返回将 nums 中所有元素变为 1 的 最少 操作次数。
示例 1:
输入:nums = [0,1,1,0,1]
输出:4
解释:
我们可以执行以下操作:
选择下标 i = 1 执行操作,得到 nums = [0,0,0,1,0] 。
选择下标 i = 0 执行操作,得到 nums = [1,1,1,0,1] 。
选择下标 i = 4 执行操作,得到 nums = [1,1,1,0,0] 。
选择下标 i = 3 执行操作,得到 nums = [1,1,1,1,1] 。
示例 2:
输入:nums = [1,0,0,0]
输出:1
解释:
我们可以执行以下操作:
选择下标 i = 1 执行操作,得到 nums = [1,1,1,1] 。
说明:
- 1 <= nums.length <= 10^5
- 0 <= nums[i] <= 1
思路
有一个二进制数组 nums
,每一次操作可以将当前元素以及之后的元素反转,问将所有元素变为 1
的最少操作次数。
这与昨天的题目 3191.使二进制数组全部等于1的最少操作次数I 类似,那个是将当前元素及后面两个元素反转。
还沿用昨天的思路,遇到 0
就进行操作,每一次操作需要对大量元素进行取模运算,因此考虑使用差分数组。这里差分数组初始均为 0
,每次操作是针对当前元素及以后的所有元素,无需考虑后续的减法操作,因此只需要一个变量计数即可。
网友最快的算法并非使用变量计数然后判断奇偶性,考虑到最终目标是将所有元素都变为 1
,每一次操作会将自身与其后的元素反转,对于初始数组任意位置 i
,如果它为 0
,该位置一定需要执行奇数次操作,因为执行偶数次反转最后还是 0
。同理,如果为 1
,需要执行 偶数 次操作。实际上每个位置是否需要执行操作是 确定的。
只要有一个初始条件,向后遍历的时候直接根据前一个元素与当前元素的关系判断是否需要累加操作即可,具体来说,如果它们值相同则不需要操作,如果不同则需要操作,直接累加这两个元素的异或值即可。
代码
/**
* @date 2024-10-19 17:30
*/
public class MinOperations3192 {
public int minOperations_v2(int[] nums) {
int n = nums.length;
int prev = nums[0];
int res = prev ^ 1;
for (int i = 1; i < n; i++) {
res += prev ^ nums[i];
prev = nums[i];
}
return res;
}
public int minOperations_v1(int[] nums) {
int n = nums.length;
int res = 0;
for (int i = 0; i < n; i++) {
if (((res % 2 ^ nums[i]) == 0)) {
res++;
}
}
return res;
}
}