美文网首页
算法学习:位运算

算法学习:位运算

作者: alex很累 | 来源:发表于2023-11-18 16:05 被阅读0次

    一、基础知识

    1.1 位运算符


    异或操作的一些特点
    x ^ 0 = x
    x ^ 1s = ~x // 注意 1s = ~0
    x ^ (~x) = 1s
    x ^ x = 0
    c = a ^ b => a ^ c = b, b ^ c = a // 交换两个数
    a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c // 随意组合
    

    1.2 位运算

    常用的位运算操作
    1. x 最右边的 n 位清零:x & (~0 << n)
    2. 获取 x 的第 n 位值(0 或者 1): (x >> n) & 1
    3. 获取 x 的第 n 位的幂值:x & (1 << (n -1))
    4. 仅将第 n 位置为 1x | (1 << n)
    5. 仅将第 n 位置为 0x & (~ (1 << n))
    6. x 最高位至第 n 位(含)清零:x & ((1 << n) - 1)
    7. 将第 n 位至第 0 位(含)清零:x & (~ ((1 << (n + 1)) - 1))
    实战位运算要点
    • 判断奇偶:
      x % 2 == 1 —> (x & 1) == 1
      x % 2 == 0 —> (x & 1) == 0
    • x >> 1 —> x / 2
      即: x = x / 2; —> x = x >> 1;
      mid = (left + right) / 2; —> mid = (left + right) >> 1;
    • X = X & (X-1) 清除最低位的 1
    • X & -X => 得到最低位的 1
    • X & ~X => 0

    二、算法实战

    191. 位1的个数

    问题描述

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

    示例
    输入:n = 00000000000000000000000000001011
    输出:3
    解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
    
    输入:n = 00000000000000000000000010000000
    输出:1
    解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
    
    输入:n = 11111111111111111111111111111101
    输出:31
    解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
    注意:这里的二进制表示有符号整数 -3。
    
    解题思路
    1. 调用java内置函数。
    2. 位运算:循环检查二进制数。
    3. 位运算优化:清零最低位的 1,直到n等于0
    代码示例
    1. 调用java内置函数
    public class Solution {
        public int hammingWeight(int n) {
            return Integer.bitCount(n);
        }
    }
    
    1. 循环检查
    public class Solution {
        public int hammingWeight(int n) {
            int count = 0;
            for (int i = 0; i < 32 && n != 0; i++) {
                if ((n & 1) == 1) {
                    count++;
                };
                n = n >> 1;
            }
            return count;
        }
    }
    
    1. 清零最低位
    public class Solution {
        public int hammingWeight(int n) {
            int count = 0;
            while (n != 0) {
                count++;
                n = n & (n - 1);
            }
            return count;
        }
    }
    

    231. 2 的幂

    问题描述

    给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false
    如果存在一个整数 x 使得 n == 2^x ,则认为 n2 的幂次方。

    示例
    输入:n = 1
    输出:true
    解释:2^0 = 1
    
    输入:n = 4
    输出:true
    
    输入:n = 5
    输出:false
    
    解题思路

    step1: 如果n是负数,不满足条件,直接返回false
    step2: 如果n2 的幂次方,那么二进制的表达中有且仅有11;我们可以清零n最低位的 1然后判断是否结果为0即可。

    代码示例
    class Solution {
        public boolean isPowerOfTwo(int n) {
            return  n > 0 && (n & (n - 1)) == 0;
        }
    }
    

    190. 颠倒二进制位

    问题描述

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

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

    循环求解,从n的低位开始,放到结果的高位上去。

    代码示例
    public class Solution {
        public int reverseBits(int n) {
            int res = 0;
            for (int i = 0; i < 32 && n != 0; i++) {
                int temp = n & 1;
                res |= (temp << 31 - i);
                n = n >>> 1;
            }
            return res;
        }
    }
    

    52. N 皇后 II

    问题描述

    n皇后问题研究的是如何将n个皇后放置在n × n的棋盘上,并且使皇后彼此之间不能相互攻击。
    给你一个整数n,返回 n皇后问题 不同的解决方案的数量。

    示例
    解题思路

    在接触位运算之前,我们常用的解题思路是dfs+回溯,在验证行、列、两条斜线成功后进行递归的下探;
    在这里,我们可以用二进制数表示列、两条斜线的情况,然后通过位运算操作得到可以放置皇后的位置。

    代码示例
    class Solution {
        public int totalNQueens(int n) {
            return dfs(n, 0, 0, 0, 0);
        }
    
        /**
         * @param n   n皇后
         * @param row 当前层数
         * @param c   列占用
         * @param s1  斜线1占用
         * @param s2  斜线2占用
         * @return
         */
        public int dfs(int n, int row, int c, int s1, int s2) {
            if (row == n) {
                return 1;
            }
    
            int count = 0;
            // 可以使用的位置
            int pos = ((1 << n) - 1) & (~(c | s1 | s2));
            while (pos != 0) {
                // 得到最低位的1
                int temp = pos & (-pos);
                // 在pos中,清除最低位的1
                pos = pos & (pos - 1);
                count += dfs(n, row + 1, c | temp, (s1 | temp) >> 1, (s2 | temp) << 1);
            }
            return count;
        }
    }
    

    338. 比特位计数

    问题描述

    给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

    示例
    输入:n = 5
    输出:[0,1,1,2,1,2]
    解释:
    0 --> 0
    1 --> 1
    2 --> 10
    3 --> 11
    4 --> 100
    5 --> 101
    
    解题思路
    0 --> 0
    1 --> 1
    2 --> 10
    3 --> 11
    4 --> 100
    5 --> 101
    6 --> 110
    7 --> 111
    8 --> 1000
    

    观察数据,可以发现dp方程:

    • 如果是偶数,dp = dp[i / 2]
    • 如果是奇数,dp = dp[i - 1] + 1 = dp[(i - 1) / 2] + 1 = dp[i / 2] + 1
      其中,偶数无+1,奇数有+1
    代码示例
    class Solution {
        public int[] countBits(int n) {
            int[] res = new int[n + 1];
            for (int i = 1; i <= n; i++) {
                res[i] = res[i / 2] + (i & 1);
            }
            return res;
        }
    }
    

    相关文章

      网友评论

          本文标题:算法学习:位运算

          本文链接:https://www.haomeiwen.com/subject/fxqpwdtx.html