JavaScript刷LeetCode拿offer-位运算

前言

经常会有人问,作为前端,你在实际工作中用到过哪些算法,而我回答一般是,树和位运算;

想想 webpack 上的那些依赖的版本类型,想想 react 源码中的那些 flag 的定义和运算,我觉得还是很有必要去学习一下位运算到底能解决一些什么问题

正文

其实位运算最典型的就运算符号就是,| & ^ 三个,但是运用到具体题目上就很灵活了,基本这个系列也只是复习一下,知道一下如何用二进制的位来存储获取值,而用二进制位这样的数据结构时,位运算就是关联使用的算法了;

其他的,我也不知道啊,就是觉得位运算好酷,有一些特殊的题目,直接用位运算就能几行解决,所以学学可以装个逼,因此这个系列暂时比较少,就两套经典题而已,以后在补充吧;

PS: 其实整理题目至此,已经有 6 组了,最初是为了复习写过的代码,但是越写越觉得自己懂的少,开始疲惫的,但是坚持下去应该会有收获的吧,加油💪

题解

136. 只出现一次的数字

只出现一次的数字 – 所有题目都是线性时间复杂度,空间复杂度都是常数级复杂度

分析
分析 – 1个单值,其余是两个

  1. 已知 a ^ a = 0, 0 ^ a = a ,
  2. 所以将 nums 中所有值进行异或处理,出现两次的都会被消除,而最后的结果就是唯一一次出现的那个值
  3. 时间复杂度 O(N),空间复杂度O(1)
var singleNumber = function(nums) {
   
    return nums.reduce((prev,cur) => prev ^ cur,0) // 0 和任何值异或都等于任何值,所以以 0 为初始值
};

137. 只出现一次的数字 II

分析 – 1个单值 x ,其余是 3 个 y1,y2…

  1. 将 nums 数组与 [0,31] 的位进行 & 比较,找出在这个位上存在的值的数量 count;
  2. 如果 count 整除 3, 证明这个位上只存在 yi;如果不整除,证明单值 x 在这个位上,那么结果要加上这个位
  3. 注意,由于 num 的取值范围是 [-pow(2,31),pow(2,31)-1], 所以第 31 位 是可以取到的,所以遍历的时候要遍历到第 31位,取到正负值;
  4. 时间复杂度 O(31∗N),空间复杂度O(1)
/** * @分析 --- 一个值出现 1 次,其余值出现 3次 -- * 1. 将所有值相加,转成二进制,然后相同的值在同一个位上肯定也是一样的,然后对每一个位进行除 3 取余,得到的值就是唯一一个出现 1 次的值了 */
var singleNumber = function (nums) {
   
  let ret = 0;
  for (let i = 0; i < 32; i++) {
   
    const temp = 1 << i;
    let count = 0;
    nums.forEach((num) => {
   
      if (num & temp) count++;
    });
    // 在 i 这个位上,有 count 这么多个值
    if (count % 3) ret |= temp;
  }
  return ret;
};


260. 只出现一次的数字 III

只出现一次的数字 – 所有题目都是线性时间复杂度,空间复杂度都是常数级复杂度

参考视频:传送门

分析

  1. 如果题目看错是只有一个值出现一次,其余都出现两次,那么直接异或就可以得出结果;
  2. 现在是有两个值只出现一次,所以异或和得到的就是这两个值的异或和,所以需要将原数组拆解成两份
    • 两份里分别存在一个只出现一次的值x1 和 x2
    • 相同的两个值要分在同一组
  3. 为了实现 2 中的条件,我们需要找出一个值 temp,让数组中的值和 temp 进行一定的比较分成两组,这时候考虑使用二进制中的位值
  4. 先用异或将所有 nums 中的值进行运算,得到 x1 ^ x2 的值 res,
  5. 对于 res,我们知道他们是由两个值 x1,x2 异或得到,也就是说,对于res,在某一个位上有值,那么另外一个肯定不在这个位上,不然就相互抵消了
  6. 所以找出第一个存在的位 bite 和对应的值 temp,然后这个时候就变成了,找出唯一一个单值,它存在于位 bite 上
  7. 时间复杂度 O(N),空间复杂度O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值