一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
954 二倍数对数数组
题目
给定一个长度为偶数的整数数组 arr,只有对 arr 进行重组后可以满足 “对于每个 0 <= i < len(arr) / 2,都有 arr[2 * i + 1] = 2 * arr[2 * i]” 时,返回 true;否则,返回 false。
目的解析
根据这个题目的说明,我们可以得知,最终是将数组重组成一个索引值为偶数时,下一个索引值的value值为该value值的两倍的新数组
做法分析
①我们第一步肯定是想将数组从小到大排序,这样才能通过小值去找到符合条件的大值/n 但是这里存在着一个特殊的情况,就是负值的情况,对于负值我们需要将它从大到小排序
②如果只是排序就会发现一个问题,位置问题, 我们是根据大小排序的,存在着下一个偶数项的值刚好是上一个偶数项的值的两倍,例如排序得到的数组是【2,3,4,6】 要求的数组是【2,4,3,6】,我们就需要加多一个Map,用来记录每个值被使用过的情况,同时在循环的底部加一个索引值的查找,因为存在这这种情况【2,4,5,10】,我们直接遍历数组的前一半部分, 只能得到2 和 4 ,但是4是被使用过的了,所以就需要跳过4去到5这里
代码
// 重组得到一个 每项偶数索引值等于它下一个索引值的二分之一 的新数组
// 难度: 正负值的处理、是否需要排序,如果需要,怎么排,不需要,怎么做
let leftStack = [] ,rightStack = [];
const map = new Map();
for(let i = 0; i < arr.length; i++){
map.set(arr[i],map.has(arr[i]) ? map.get(arr[i]) + 1 : 1)
if(arr[i] < 0){
leftStack.push(arr[i])
}else{
rightStack.push(arr[i])
}
}
leftStack = leftStack.sort((a,b) => b - a);
rightStack = rightStack.sort((a,b) => a - b);
let result = true;
let l = 0,indexLeft = 0;
let num = 0;
while(l < (leftStack.length / 2)){
num = leftStack[indexLeft] * 2;
map.set(num / 2,map.get(num / 2) - 1)
if(map.get(num)){
map.set(num,map.get(num) - 1)
}else{
result = false;
break;
}
l++;
while(!map.get(leftStack[++indexLeft]) && indexLeft < leftStack.length - 1){}
}
// 负数组不对就直接退出可以了
if(!result){
return false;
}
let r = 0,indexRight = 0;
while(r < (rightStack.length / 2)){
num = rightStack[indexRight] * 2;
map.set(num / 2,map.get(num / 2) - 1)
if(map.get(num)){
map.set(num,map.get(num) - 1)
}else{
result = false;
break;
}
r++;
while(!map.get(rightStack[++indexRight]) && indexRight < rightStack.length - 1){}
}
return result
};
优化
由于使用了Map,知道了数值和它在数组中有多少个
我们就把题目转成数值理解,就等于我需要判断数组是否存在这样的关系,0的次数为偶数,小的值和它两倍大的值的数量是否一致
优化代码
var canReorderDoubled = function(arr) {
arr = arr.sort((a,b)=>{
if(a < 0 && b < 0){
return b - a
}else{
return a - b
}
})
const map = new Map();
arr.forEach(item => {
map.set(item,map.get(item) ? map.get(item) + 1 : 1)
})
for(let [key,value] of map){
// 当前值已经使用过了
if(value === 0) continue
// 0的情况
if(key === 0){
if(value % 2 !== 0){
return false
}
}else{
// 该值不存在 或者 数量少
if(map.get(key * 2) == undefined || map.get(key * 2) < value){
return false
}else{
map.set(key,0);
map.set(key * 2, map.get(key * 2) - value);
}
}
}
return true;
};
总结:优化后的代码更好理解,空间复杂度上也有优化,因为不需要用栈去区分当前的正负值了,排列好后,在Map中统计好数目就可以直接遍历使用,时间复杂度为数组中不同数字出现的次数