位运算 - 前进四格

115 阅读4分钟

程序中的所有数在计算机内存中都是以二进制的形式存储;由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快

符号描述规则
&
|
异或二进制位上相同为0,不同为1
<<左移各二进制位全部左移若干位,高位丢弃,低位补0
>>右移无符号数:高位补0;有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

-#### 136. 只出现一次的数字

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

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

示例 1:
输入: [2,2,1]
输出: 1

解题思路

1.可以想要使用字典
2.使用位运算: x ^ x = 0, 相同的元素异或后消消乐 0 ^ x = x

代码实现

def singleNumber( nums): 
    res = 0 
    for num in nums: 
        res ^= num 
    return res

or

def singleNumber(nums):
    return reduce(lambda x, y: x ^ y, nums)
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为[汉明重量])。

示例1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'

解题思路

 1.清零最低位1的方法: x & (x - 1)
 2.当每次遍历的值不为0时,进入清零的逻辑中

解题思路

代码实现

def hammingWeight(n):
    ret = 0
    # 非零的情况(表示还有为1的二进制位)
    while n:
        n &= n - 1  # 低位清零
        ret += 1
    return ret
给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。
如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。

示例 1:
输入: n = 1
输出: true
解释: 20 = 1

解题思路

如果整数是2的幂次方:
1.该数 > 0
1.表示该数只有一个二进制位为1。

解题思路

代码实现

def isPowerOfTwo(n):
    return n > 0 and (n & (n - 1)) == 0
给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

示例 1:
输入: n = 2
输出: [0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10

解题思路

通常而言,可以在每到一个数时就独立的计算某个元素1的个数;
但是正常来说:每个元素和之前元素是存在 + 1的关系的,是不是代表二进制位1的个数有什么关联呢?
当在由小范围推导整体,元素间存在重叠关系时,就该想到动态递归思路:
    dp[x] = dp[x & (x - 1)] + 1
当前元素1的个数 = 上一个元素(该元素低位清零对应的值) + 1(当前清零的1位)

解题思路

实现代码

def countBits(n):
    res = [0] * (n + 1)
    for i in range(1, n + 1):
        res[i] = res[i & (i - 1)] + 1
    return res
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例 1:
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。

解题思路

转换成以位运算的方式思考:(N = 4)
1.每一行只能放置1个棋子,那么存在四种放置方式 1000\0100\0010\0001 
2.当上一回放置1个棋子后,本行的限制条件包括 cols、diagonals1、diagonals2

解题思路

比如:当确认了第一行、第二行后,第三行的限制条件怎么确认呢?

解题思路

当拿到所有的限制条件后,如何得到所有的可选位? 解题思路

拿到的可选位,类似如:1010000,那么如何一位位的获取呢?

通过遍历,不断的拿到最低位的零:
while bits:
    # 拿到最后一位 1 
    p = bits & (-bits)
    
    doSomething()....
    
    # 清除之前拿到过的最后一位非0位
    bits &= (bits - 1)

代码实现

部分实现代码
def solveNQueens(n):
    count = 0
    def dfs(row = 0, col = 0, pie = 0, na = 0):
        # 结束条件
        if row >= n:
            nonlocal count
            count += 1
            return
        # 小心小于零的情况(1出现的位置超出了 N 的限制)
        bits =(~(col|pie|na)) & ((1<<n) - 1)
        # 当还有空位时
        while bits:
            # 拿到最低位的1
            p = bits & (-bits)
            dfs(row + 1, col|p, (pie | p) << 1, (na|p)>>1)
            # 清零最低位的1
            bits &= (bits - 1)
    dfs()
    return count