「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战」。
每日刷题第46天 2021.02.13
6005.使数组变成交替数组的最少操作数
- leetcode原题链接:leetcode-cn.com/problems/mi…
- 难度:中等
- 方法:贪心、哈希表、排序
题目
- 给你一个下标从 0 开始的数组 nums ,该数组由 n 个正整数组成。
- 如果满足下述条件,则数组 nums 是一个 交替数组 :
nums[i - 2] == nums[i] ,其中 2 <= i <= n - 1 。
nums[i - 1] != nums[i] ,其中 1 <= i <= n - 1 。
- 在一步 操作 中,你可以选择下标 i 并将 nums[i] 更改 为 任一 正整数。
- 返回使数组变成交替数组的 最少操作数。
示例
- 示例1
输入:nums = [3,1,3,2,4,3]
输出:3
解释:
使数组变成交替数组的方法之一是将该数组转换为 [3,1,3,1,3,1] 。
在这种情况下,操作数为 3 。
可以证明,操作数少于 3 的情况下,无法使数组变成交替数组。
- 示例2
输入:nums = [1,2,2,2,2]
输出:2
解释:
使数组变成交替数组的方法之一是将该数组转换为 [1,2,1,2,1].
在这种情况下,操作数为 2 。
注意,数组不能转换成 [2,2,2,2,2] 。因为在这种情况下,nums[0] == nums[1],不满足交替数组的条件。
提示
1 <= nums.length <= 1051 <= nums[i] <= 105
解法
分析情况,进行判断
- 首先,从手写思考样例可以得到,最终的交替数组形式均为
[a,b,a,b,a,b,a] 或 [a,b,a,b,a,b]的形式。因此可以贪心的想,取a和b均为数组中最长的两个数,那么需要修改的数值就会最少。此处的a必须是偶数位最多的数,b必须是奇数位最多的数。 - 使用
map集合统计奇数mapOdd和偶数mapEven的数值出现的次数,并降序排序。取排好序后的两个数组的最大值,即:当前偶数位和奇数位的最多的值。判断这个两个值是否相等? - 不相等:最小操作数
ans= 数组的长度len- (奇数最多的值次数 + 偶数最多的值次数) - 相等:
- 判断偶数最多的值出现的次数 < 奇数最多的值出现的次数。选择更换较小的一方(偶数最多的值出现的次数),取其次长的数值出现的次数 和 奇数最多的值出现的次数。
- 偶数最多的值出现的次数 > 奇数最多的值出现的次数。选择更换较小的一方(奇数最多出现的次数),取其次长的数值出现的次数 和 偶数最多的值出现的次数。
- 偶数最多的值出现的次数 = 奇数最多的值出现的次数。没有更小的一方,因此两边均需要取次长的计算,并将两值进行比较。
- 注:每次选择更换最小的一方,是因为贪心的思想,保留最大的,更换最小的。
var minimumOperations = function(nums) {
let len = nums.length;
if(len < 2) return 0;
// 奇数
let mapOdd = new Map();
// 偶数
let mapEven = new Map();
// 记录下来数据
for(let i = 0; i < len; i++) {
if(i % 2 == 0){
if(mapEven.has(nums[i])){
mapEven.set(nums[i], mapEven.get(nums[i]) + 1);
}else {
mapEven.set(nums[i], 1);
}
}else {
// 奇数
if(mapOdd.has(nums[i])){
mapOdd.set(nums[i], mapOdd.get(nums[i]) + 1);
}else {
mapOdd.set(nums[i], 1);
}
}
}
// 排序
let evenArr = [...mapEven.entries()];
let oddArr = [...mapOdd.entries()];
evenArr.sort((a,b) => b[1] - a[1]);
oddArr.sort((a,b) => b[1] - a[1]);
// console.log(evenArr,oddArr);
// 判断情况
let ans = 0;
let lenOdd = oddArr.length;
let lenEven = evenArr.length;
let tempt;
if(evenArr[0][0] != oddArr[0][0]){
// 不相等
ans = len - evenArr[0][1] - oddArr[0][1];
}else {
// 相等
if(evenArr[0][1] < oddArr[0][1]){
// 找小的的次长
if(lenEven > 1){
ans = len - evenArr[1][1] - oddArr[0][1];
}else {
// 不存在次长
tempt = evenArr[0][1] + oddArr[0][1];
ans = len - tempt + parseInt(tempt / 2);
}
}else if(evenArr[0][1] > oddArr[0][1]){
// 奇数的次长
if(lenOdd > 1){
// 存在次长
ans = len - oddArr[1][1] - evenArr[0][1];
}else {
// 不存在次长
tempt = oddArr[0][1] + evenArr[0][1];
ans = len - tempt + parseInt(tempt / 2);
}
}else if(evenArr[0][1] == oddArr[0][1]){
// 比较小找哪个的次长更划算
// 两个都存在次长
let min = Infinity;
if(lenOdd > 1){
min = len - oddArr[1][1] - evenArr[0][1];
}else if(lenEven > 1){
min = (len - evenArr[1][1] - oddArr[0][1]) > min ? min : (len - evenArr[1][1] - oddArr[0][1]);
}
ans = min;
// 两个都不存在次长
if(lenOdd == 1 && lenEven == 1){
ans = parseInt(len / 2);
}
}
}
return ans;
};
优化解法
- 处理数据方面都没有优化,仍然是
map和排序进行预处理。但是在判断条件方面,进行了更改。- 不相等的时候,同上。
- 相等(优化)(将情况整合后,合并为如下两种情况)
- 第一种情况:取偶数次长,奇数最长
- 第二种情况:取奇数最长,偶数次长
// 针对上面代码判断条件的整合和修改
if(evenArr[0][0] != oddArr[0][0]){
// 不相等
ans = len - evenArr[0][1] - oddArr[0][1];
}else {
// 相等,要么取奇1偶2要么取奇2偶1
ans = len - Math.max((evenArr[0][1] + oddArr[1][1]),(evenArr[1][1] + oddArr[0][1]));
}
return ans;
};