算法打卡第二十二天 (位运算)

116 阅读2分钟
  1. 剑指 Offer 56 - I. 数组中数字出现的次数
  2. 剑指 Offer 56 - II. 数组中数字出现的次数 II

剑指 Offer 56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

题意理解 找出数组中不重复的两个数 利用Map,不符合空间复杂度

  1. 两个不同的数为a=0,b=0; 0异或任意数为任意数
  2. 位运算符异或^ 两个数相同为0,假设x.y就是两个出现一次不相同的数,遍历一遍结果ret就是x^y的值
  3. 两个数不相同,x^y的二进制位一定不同,用div=1表示,对遍历ret&div==0,div<<=1查找到第一个进制位,即可拆分两个数
  4. 再次遍历数组,数组中的数据就有两种情况,一种是div&nums[i]===0)(符合条件的一个数在这里),另一种就是div&nums[i]!==0(符合条件的另一个数在这里),如果div&nums[i]===0,则a^=nums[i],否则b^=nums[i]
  5. a,b就是要找的数

位运算

var singleNumbers = function(nums) {
    let ret = 0;
    nums.forEach((n) => {
        ret ^= n;
    })
    let div = 1;
    while ((div & ret) == 0) {
        div <<= 1;
    }
    let a = 0,
        b = 0;
    nums.forEach((n) => {
        if ((div & n) != 0) {
            a ^= n;
        } else {
            b ^= n;
        }
    })
    return [a, b];
};

Map

var singleNumbers = function(nums) {
    const map = new Map()
    for (let i = 0; i < nums.length; i++) {
        if (map.has(nums[i])) {
            map.set(nums[i], 2)
        } else {
            map.set(nums[i], 1)
        }
    }
    let arr = [];
    map.forEach((val, key) => {
        if (val === 1) {
            arr.push(key)
        }
    })
    return arr
};

剑指 Offer 56 - II. 数组中数字出现的次数 II

在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

题意理解: 找出数组中只出现一次的数 位运算是都将转为32为进行计算,每位只有0和1,不能只看表象及~0因改为11111111111111111111111111111111 ~为取反0变1, 1变0 1&0=1; 1&x=x; x&~x=0 x^0=x; 1^x=~x; x^x=0 仅在二进制位中相同

  1. 需要标记出现一次 1 出现两次为 2 出现三次为 0
  2. ones 一次为1,两次三次为0;twos第二次为1,一次和三次为0
  3. 一次 ones = nums[i] = ones ^ nums[i] & ~nums[i] ;twos = 0 =twos ^ nums[i] & ~ones;
  4. 两次 ones = 0 = ones ^ nums[i] & ~nums[i] ;twos =nums[i]= twos ^ nums[i] & ~ones;
  5. 三次 ones = 0= ones ^ nums[i] & ~nums[i] ;twos = twos ^ nums[i] & ~ones;
var singleNumber = function(nums) {
    let ones = 0,
        twos = 0;
    for (let i in nums) {
        ones = ones ^ nums[i] & ~twos;
        twos = twos ^ nums[i] & ~ones;
    }
    return ones;
};

遍历统计 声明一个长度为32的数组,初始数据为0 计算数组中每隔数的每位数字出现的次数,最后遍历数组,每位求余,即可计算出不同的数字

var singleNumber = function(nums) {
    let arr = [];
    for (let i = 0; i < 32; i++) {
        arr[i] = 0;
    }
    nums.forEach(item => {
        for (let i = 0; i < 32; i++) {
            arr[i] += item & 1;
            item >>>= 1
        }
    })
    let res = 0;
    for (let i = 0; i < 32; i++) {
        res <<= 1
        res |= arr[31 - i] % 3;
    }
    return res;
}