LeetCode 刷题 --位运算

文章目录

    • 461.汉明距离
    • 191. 位1的个数
    • 190.颠倒二进制位
    • 136.只出现一次的数字
    • 268.缺失数字
    • 不用额外变量交换两个整数
    • 2的幂

461.汉明距离

两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。

给出两个整数 x 和 y,计算它们之间的汉明距离。

注意:
0 ≤ x, y < 231.

示例:

输入: x = 1, y = 4

输出: 2

解释:
1   (0 0 0 1)
4   (0 1 0 0)
       ↑   ↑

上面的箭头指出了对应二进制位不同的位置。

class Solution {
    public int hammingDistance(int x, int y) {
     //XOR(异或)相同为0,不同为1
     //统计1
     int z = x^y;
     int cnt =0;
     while(z != 0){
         //z&1即可统计出1的数目,因为只有1&1结果才能为1;
         if((z&1) == 1) cnt++;
         z = z >> 1;
     }
     return cnt;

    }
}
class Solution {
    public int hammingDistance(int x, int y) {
     //XOR(异或)相同为0,不同为1
     //统计1
     int z = x^y;
     int cnt =0;
     while(z != 0){
        //一个整数n与(n-1)做按位与,可消去n的二进制码中最低位上的1。
        z&= (z-1);
        cnt++;
     }
     return cnt;

    }
}

class Solution {
    public int hammingDistance(int x, int y) {
     //XOR(异或)相同为0,不同为1
     //统计1
     return Integer.bitCount(x^y);
    }
}

原码补码反码见这里

191. 位1的个数

编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。

示例 1:

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
想要着重说明,在数字进行右移时,需要采用>>>无符号右移,不能使用>>,会导致数字溢出

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int cnt =0;

        while( n != 0){
            if((n&1) == 1) cnt++;
            n = n >>> 1;
            //舍弃最低位,继续判断下一位(会有负数情况,因此应该使用无符号右移)
        }
        return cnt; 
    }
}

190.颠倒二进制位

颠倒给定的 32 位无符号整数的二进制位。

示例 1:

输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。

public class Solution {
    // you need treat n as an unsigned value
    //思路:取当前最后一位(n&1)
    //将最后一位移动到对应位置,即向左移动31位
    //其余的对应移动30,29,28,。。。
    //退出条件,如果剩余位数为0时,不再反转
    public int reverseBits(int n) {
        int res =0;
        for(int bitSize = 31; n !=0 ; n= n>>>1, bitSize--){
            res += (n &1) << bitSize;
        }
        return res;     
    }
}
public class Solution {
    // you need treat n as an unsigned value
    //思路:取当前最后一位(n&1)
    //将最后一位移动到对应位置,即向左移动31位
    //其余的对应移动30,29,28,。。。
    //退出条件,如果剩余位数为0时,不再反转
    public int reverseBits(int n) {
        int res =0;
        for(int i = 0 ; i<32 ;i++){
            res <<= 1;  //向左移动一位
            res += (n&1);//取出最后一位数字,补上
            n >>>= 1; //n向右移动一位

        }
        return res;
    }
}

如果该函数需要被调用很多次,可以将 int 拆成 4 个 byte,然后缓存 byte 对应的比特位翻转,最后再拼接起来。

private static Map<Byte, Integer> cache = new HashMap<>();

public int reverseBits(int n) {
    int ret = 0;
    for (int i = 0; i < 4; i++) {
        ret <<= 8;
        ret |= reverseByte((byte) (n & 0b11111111));
        n >>= 8;
    }
    return ret;
}

private int reverseByte(byte b) {
    if (cache.containsKey(b)) return cache.get(b);
    int ret = 0;
    byte t = b;
    for (int i = 0; i < 8; i++) {
        ret <<= 1;
        ret |= t & 1;
        t >>= 1;
    }
    cache.put(b, ret);
    return ret;
}

136.只出现一次的数字

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

解题技巧:
0和任何数字相异或都会得到该数字本身
1和任何数字相与都会得到该数字作为二进制数的最后一位
交换律:a ^ b ^ c = a ^ c ^ b
任何数于0异或为任何数 0 ^ n = n
相同的数异或为0: n ^ n = 0
任何数于0异或为任何数 0 ^ n = n
相同的数异或为0: n ^ n = 0

class Solution {
    public int singleNumber(int[] nums) {
    //两个相同的数异或等于0
    //找出异或不为0的数字
    int res = 0;
    //0和任何数字相异或都会得到该数字本身
    //1和任何数字相与都会得到该数字作为二进制数的最后一位
    //交换律:a ^ b ^ c = a ^ c ^ b

    //任何数于0异或为任何数 0 ^ n = n

    //相同的数异或为0: n ^ n = 0
    //2 ^ 3 ^ 2 ^ 4 ^ 4等价于 2 ^ 2 ^ 4 ^ 4 ^ 3 => 0 ^ 0 ^3 => 3
    for(int num : nums){
        res = res^num;
    }
     return res;
    }
}

268.缺失数字

给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。

class Solution {
    //思路:将数组中的数字加入到HashSet表中,
    //再遍历1-n中的数字,看哪个数字不在
    public int missingNumber(int[] nums) {
    Set<Integer> numSet = new HashSet<Integer>();
    for(int num : nums) numSet.add(num);
    for(int i = 0; i < nums.length+1; i++){
        if(!numSet.contains(i))  return i;
    }
    return -1;
    }
}
class Solution {
    //位运算
    /*
 missing  
=4∧(0∧0)∧(1∧1)∧(2∧3)∧(3∧4)
=(4∧4)∧(0∧0)∧(1∧1)∧(3∧3)∧2
=0∧0∧0∧0∧2
=2	
*/
    public int missingNumber(int[] nums) {
    int missNum = nums.length;
    for(int i= 0 ; i< nums.length; i++){
        missNum = missNum ^ i ^nums[i];
    }
    return missNum;
    }
}   

不用额外变量交换两个整数

a = a ^ b;
b = a ^ b;
a = a ^ b;

实际产生效果为:两数互换
b= a ^b ^b = a;
a = a ^ a ^ b= b;

2的幂

给定一个整数,编写一个函数来判断它是否是 2 的幂次方。

class Solution {
    public boolean isPowerOfTwo(int n) {
    //二进制的数字只有一个1,比如8 4 2 1
    //统计1的个数
    if(n< 1) return false;
    int cnt = 0;
    while( n!= 0){
        if((n &1) == 1)  {
            cnt++;  
        }
         n >>= 1;
    }
    if(cnt > 1) return false;
    return true;
    }
}

class Solution {
    public boolean isPowerOfTwo(int n) {
    //二进制的数字只有一个1,比如8 4 2 1
    //统计1的个数
    return n >0 && Integer.bitCount(n) == 1;
    }
}

你可能感兴趣的:(LeetCode刷题,#,数学类,#,位运算)