一看就会,过后就忘的位运算

50 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述:

  1. 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/si… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2.给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

 

进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/si… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、思路分析:

最容易想到的当然就是用哈希表一存,遍历一遍便得到了结果,但是空间复杂度就高了,仔细想想好像没有办法了,没有办法的时候就多往位运算去思考,位运算就是时间复杂度和空间复杂度都低的玄学,显然如果我们对所有的数进行异或那么相同的数都会变成0,那么最终剩下的就是那个只有一个的数字了。真是妙啊(代码仔代码一中);

我们再来看看第二题,显然用暴力的哈希表一样可以解决,一样的问题:空间的复杂度高了,那么没有办法了,又得想想位运算了,但是这个题目是有两个不同的数字的,这怎么办呢?分组,我们可以把这题拆成两道第一题!这样我们就可以简单的解决这题了,怎么拆呢?首先相同的数一定要在同一组中,两个只有一个的数也要在不同的组中,这样才能保证转化为第一题。我们先将所有的数进行异或,那么得到的最终的结果就是这两个目标数的异或值,显然该值不能是0(是0的话说明两个目标数是一样的,那么就不符合题意了),我们再用这个值的最低位1,进行分组,那么显然不同的数与它异或得到不同的值,分到不同的组,相同的则分到相同的组。 三、AC 代码:

代码一:

/**
 * @param {number[]} nums
 * @return {number}
 */
var findDuplicate = function(nums) {
    let fast=0,slow=0;
    while(true){
        fast=nums[nums[fast]];
        slow=nums[slow];
        if(slow===fast){
            fast=0;
            while(nums[slow]!==nums[fast]){
                fast=nums[fast];
                slow=nums[slow];
            }
            return nums[slow];
        }
    }
};

代码二:

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var singleNumber = function(nums) {
  let xor = 0
  for (let i = 0; i < nums.length; i++) {
    xor ^= nums[i]
  }
  let mask = xor & (-xor)//求出最低位的1
  let ans = Array(2).fill(0);
  for (let i = 0; i < nums.length; i++) {
    if ((nums[i] & mask) === 0) {//分组
      ans[0] ^= nums[i]
    } else {
      ans[1] ^= nums[i]
    }
  }
  return ans
}

四、总结:

位运算有时候会有奇特的效果,在穷途末路的时候不如往位运算方向想想,可能就会又思路了。