题目
给定一个长度为偶数的整数数组 arr,只有对 arr 进行重组后可以满足 “对于每个 0 <= i < len(arr) / 2,都有 arr[2 * i + 1] = 2 * arr[2 * i]” 时,返回 true;否则,返回 false。
思路
我们细看下题目,再带入几个例子就可以发现
i=0 arr[1]==2*arr[0];
i=1 arr[3]=2*arr[0]
所以题目就是想求给出的数组是否可以拆分成n/2个数对,每个数对中其中一个是另一个二倍
解法
排序遍历
- 最直白的就是对数组进行排序,然后遍历。
- 我们先设定一个数对中较小的一位,然后判断剩下的数组中是否包含他的二倍数
- 如果不包含,则返回false
- 如果包含,则把当前数和他的二倍数从数组中移除
- 并把数组更新,然后判断下一位
- 直到数组为空为止 跳出循环返回true
var canReorderDoubled = function(arr) {
arr.sort((a,b)=>Math.abs(a)-Math.abs(b));
while(arr.length>0){
let afterArr=arr.slice(1);
let doubleIndex=afterArr.indexOf(2*arr[0]);
if(doubleIndex!==-1){
afterArr.splice(doubleIndex,1);
arr=afterArr;
}else{
return false
}
}
return true
};
这个解法理解起来简单 ,但是 超时了。。。
哈希表+排序
这个题解参考了官方题解。
- 建立一个哈希表,存储数组中数值出现的次数
- 判断个例,因为0的2倍数是0,所以0出现的次数如果是奇数,则返回false
- 然后获取数组中出现的数,并进行排序,按照其绝对值升序
- 遍历升序排列后的数组
- 当前数值x,如果在表中没有找到2x,或者2x的出现的次数小于x出现的次数,说明会有一个x落单,所以返回false
- 如果2x的出现的次数足够大,则减去x出现的次数,表示x都已和2x匹配上,更新2x的个数
var canReorderDoubled = function(arr) {
let countMap=new Map();
for(let i of arr){
countMap.set(i,(countMap.get(i)||0)+1 );
}
if((countMap.get(0)||0)%2==1) return false;
let keysArr=[];
for(let key of countMap.keys()){
keysArr.push(key)
}
keysArr.sort((a,b)=>
Math.abs(a)-Math.abs(b)
)
for(let x of keysArr){
if((countMap.get(2*x)||0)<countMap.get(x)){
return false;
}
countMap.set(2*x,(countMap.get(2*x)||0)-countMap.get(x))
}
return true
};
今日打卡结束