leetcode每日一题:二倍数对数组

131 阅读1分钟

题目

给定一个长度为偶数的整数数组 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
};

今日打卡结束