LeetCode 今日四题//位运算//11.18Hot..

第二题不是位运算,可以先看。

剩下三道从简单到难:4=>3=>1

只出现一次的数字系列(均可位运算):

1.相同的出现三次,多余一个不相同的

剑指 Offer 56 - II

数组中数字出现的次数 II  

33679.2%中等
137

只出现一次的数字 II  

28668.2%中等

 两题一样

法一:sort+比较相邻元素

var singleNumber = function(nums) {
    nums.sort();
    if(nums[0] !== nums[1]) return nums[0];
    if(nums[nums.length-1] !== nums[nums.length-2]) return nums[nums.length-1];
    for(let i = 1; i < nums.length - 1; i++){
        if(nums[i] !== nums[i-1] && nums[i] !== nums[i+1]) return nums[i];
    }
    // return null;
};

感觉没有把题给条件(出现三次)全部用上,此法有点太丑

补充:for循环几种方式:

① 普通for(let i=0;i<arr.length;i++)

②for in    : for(let x in arr) 其中x也是索引,若arr换为obj,则x为键

③for of(ES6):for(let num of nums) 其中num是元素

法二:创建对象+ES6 for of

var singleNumber = function(nums) {
    // 创建对象。for of
    let obj = {};
    for(let x of nums) {
        obj[x]? obj[x]++ :obj[x] = 1;
    } 
    for(let x in obj) {
        if(obj[x] == 1) return x;
    }
};

但有更好的方法:位运算。

法三:

var singleNumber = function(nums) {
    let res = 0;
    for (let bit = 0; bit < 32; bit++){
        let count = 0;
        let mask = 1<<bit;
        for(let n of nums) {
            if((mask & n) !== 0) count++;
        }
        if(count % 3) res = res | mask;
    }
    return res;
};

用到了位与,位或,移位

声明一个mask,mask的1从最后一位逐渐往前移动,和数组内的各元素的二进制的某一位比较,计数count,内层循环结束后将mask和res取或。

“如果一个数字出现3次,它的二进制每一位也出现的3次。如果把所有的出现三次的数字的二进制表示的每一位都分别加起来,那么每一位都能被3整除。 我们把数组中所有的数字的二进制表示的每一位都加起来。如果某一位能被3整除,那么这一位对只出现一次的那个数的这一肯定为0。如果某一位不能被3整除,那么只出现一次的那个数字的该位置一定为1。”

2.= =

剑指 Offer 55 - I

二叉树的深度  

66278.7%简单

这几道位运算的题中我穿插了一道递归二叉树深度...

直接递归做:不断找左子树和右子树中的最大值,直接return,最后加1

var maxDepth = function(root) {
    if(!root) return 0; //终止条件
    return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
};

 3.相同的出现两次,多出的两个各不相同

剑指 Offer 56 - I

数组中数字出现的次数  

60970.9%中等
260

只出现一次的数字 III  

24374.0%中等

 两题一样

如果没有空间复杂度O(1)的条件,可以用for来做

var singleNumbers = function(nums) {
    let obj = {};
    let arr = [];
    for(let num of nums) {
        obj[num]? obj[num]++ : obj[num] = 1;
    }
    for(let num in obj) {
        if(obj[num] == 1) arr.push(num);
    }
    return arr;
};

 但不符题意,而且好像很蠢...

 用位运算:异或

①异或的性质
两个数字异或的结果a^b是将 a 和 b 的二进制每一位进行运算,得出的数字。 运算的逻辑是
如果同一位的数字相同则为 0,不同则为 1

②异或的规律

任何数和本身 异或 == 0

任何数和 0 异或 == 本身,可用n & 1 == 1或0来判断n的奇偶性,即最后一位是否是1

③异或满足交换律。 即 a ^ b ^ c ,等价于 a ^ c ^ b

var singleNumbers = function(nums) {
    let a = 0;
    let index = 0;
    for(let num of nums) {
        a ^= num;
    }
    while((a & 1) ==0){
        index++;
        a >>= 1;
    }
    let r1 = 0;
    let r2 = 0;
    for(let num of nums) {
        // 以4,4,1,6为例,分为441和6这两组
        if (((num >> index) & 1) == 0){
            r1 ^= num;
        } else {
            r2 ^= num;
        }
    }
    return [r1,r2];
};

4.相同的出现一次,只多出一个不同的数

136

只出现一次的数字  

124870.3%简单

此题比上题简单,因为只需提取1个数据,直接异或然后返回结果即可

var singleNumber = function(nums) {
    let a = 0;
    for (let n of nums) {
        a ^= n;
    }
    return a;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值