位运算合集

题目

位运算分为两类:

1.逻辑位运算符

(1)位与( & )
当 两位 都为1时,结果为1
(2) 位或( | )
当且仅当两位都为0时,结果为0
(3) 异或( ^ )
当且仅当两位不同时,结果为1  
(4) 按位取反( ~ )
1---0  0---1

2.位移运算符

(1)左移(<<)
	末位补0。左移是指的二进制这串数字往左移动
(2)右移(>>)
	负数补1,非负数补零

231. 2 的幂

  • 给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。

如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。

示例 1:

输入:n = 5
输出:false

示例 2:

输入:n = 16
输出:true
解释:24 = 16

题解

class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
        if n <= 0:
            return False
        else:
            if (n & (n-1))==0:
                return True
            else:
                return False

342. 4的幂

  • 给定一个整数,写一个函数来判断它是否是 4 的幂次方。如果是,返回 true ;否则,返回 false 。

整数 n 是 4 的幂次方需满足:存在整数 x 使得 n == 4x

示例 1:

输入:n = 16
输出:true

示例 2:

输入:n = 5
输出:false

题解

  • 当一个数是2的偶数次幂(比如24可以化为42),当为2的奇数次幂(比如2^3不可以化为4的幂)。可以用n除以3,如果余1则为2的偶数次幂,如果余2则为2的奇数次幂。
  • 所以本题只需要判断n是否为2的幂,并且用除以3通过余数判断是2的偶数次幂来解决。
class Solution:
    def isPowerOfFour(self, n: int) -> bool:
        if n <= 0:
            return False
        else:
            if (n & (n-1))==0 and n%3==1:
                return True
            else:
                return Falsee

191. 位1的个数

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

示例 1:

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

示例 2:

输入:n = 11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。

题解

  • n & (n - 1) ,这个代码可以把 n 的二进制中,最后一个出现的 1 改写成 0。使得 n 变成 0 的操作次数,就是 n 的二进制中 1 的个数。
  • 与&:全1为1。比如n=3,则n & (n - 1):3&2=11&10=10可以发现进行一次n & (n - 1)后11的最后一位1变成了0即10。解决本题n中1的个数只需要统计n变成0需要几次n & (n - 1)即可
class Solution(object):
    def hammingWeight(self, n):
        res = 0
        while n:
            res += 1
            n &= n - 1
        return res

面试题 16.01. 交换数字(中)

  • 编写一个函数,不用临时变量,直接交换numbers = [a, b]中a与b的值。

示例 1:

输入: numbers = [1,2]
输出: [2,1]

题解

  • 异或^:a ^ 0 = a;a ^ a=0,并且满足交换律结合律
  • 例子交换a,b:

a = a ^ b
b = a ^ b=(带入上面a)a ^ b ^ b=(结合律)a ^ 0=a
a = a ^ b =a ^ b ^ a =(带入上面a,b)a ^ a ^ b=(交换律)0 ^ b=b

class Solution:
    def swapNumbers(self, numbers: List[int]) -> List[int]:
        numbers[0]=numbers[0]^numbers[1]
        numbers[1]=numbers[0]^numbers[1]
        numbers[0]=numbers[0]^numbers[1]
        return numbers

136. 只出现一次的数字

  • 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
    你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例 1:

输入:nums = [2,2,1]
输出:1

示例 2:

输入:nums = [4,1,2,1,2]
输出:4

题解

  • 异或^:a ^ 0 = a;a ^ a=0,并且满足交换律结合律
  • 只需要对数组里面的元素做异或操作,只要有相同的都会为0,最后剩下的那个与0异或为他本身,返回即可
class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        x=0
        for num in nums:
            x ^= num
        return x

461. 汉明距离

  • 两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。
    给你两个整数 x 和 y,计算并返回它们之间的汉明距离。

示例 1:

输入:x = 1, y = 4
输出:2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
..........↑....↑
上面的箭头指出了对应二进制位不同的位置。

示例 2:

输入:x = 3, y = 1
输出:1

题解

  • 异或^:a ^ 0 = a;a ^ a=0
  • 二进制都是0/1,x ^ y相同的位置0,不同的位置为1,汉明距离要求的是二进制不同的位置数目,转化为统计异或后数的1的个数。
class Solution:
    def hammingDistance(self, x: int, y: int) -> int:
        n=x^y
        res  = 0
        while n:
            res+=1
            n &=n-1
        return res

693. 交替位二进制数

  • 给定一个正整数,检查它的二进制表示是否总是 0、1 交替出现:换句话说,就是二进制表示中相邻两位的数字永不相同。

示例 1:

输入:n = 5
输出:true
解释:5 的二进制表示是:101

示例 2:

输入:n = 7
输出:false
解释:7 的二进制表示是:111.

示例 3:

输入:n = 11
输出:false
解释:11 的二进制表示是:1011.

题解

  • 与&:都为1才为1
  • n的二进制与3的二进制11&,满足要求的是01&11=01或10&11=10,如果n为00则00&11=00,n为11则11&11=11,当与的结果为00或11时(十进制为0、3)返回False,其他返回True,并且要对n的二进制循环右移检查
  • 右移是指n的二进制这串数字往右移动
class Solution:
    def hasAlternatingBits(self, n: int) -> bool:
        while n:
            if n&3==3 or n&3==0:
                return False
            n >>=1
        return True

1863. 找出所有子集的异或总和再求和

  • 一个数组的 异或总和 定义为数组中所有元素按位 XOR 的结果;如果数组为 空 ,则异或总和为 0 。
    例如,数组 [2,5,6] 的 异或总和 为 2 XOR 5 XOR 6 = 1 。
    给你一个数组 nums ,请你求出 nums 中每个 子集 的 异或总和 ,计算并返回这些值相加之 和 。

示例 1:

输入:nums = [1,3]
输出:6
解释:[1,3] 共有 4 个子集:

  • 空子集的异或总和是 0 。
  • [1] 的异或总和为 1 。
  • [3] 的异或总和为 3 。
  • [1,3] 的异或总和为 1 XOR 3 = 2 。
    0 + 1 + 3 + 2 = 6

示例 2:

输入:nums = [5,1,6]
输出:28
解释:[5,1,6] 共有 8 个子集:

  • 空子集的异或总和是 0 。
  • [5] 的异或总和为 5 。
  • [1] 的异或总和为 1 。
  • [6] 的异或总和为 6 。
  • [5,1] 的异或总和为 5 XOR 1 = 4 。
  • [5,6] 的异或总和为 5 XOR 6 = 3 。
  • [1,6] 的异或总和为 1 XOR 6 = 7 。
  • [5,1,6] 的异或总和为 5 XOR 1 XOR 6 = 2 。
    0 + 5 + 1 + 6 + 4 + 3 + 7 + 2 = 28

示例 3:

输入:nums = [3,4,5,6,7,8]
输出:480
解释:每个子集的全部异或总和值之和为 480 。

题解

  • 与&:都为1才为1
  • n的二进制与3的二进制11&,满足要求的是01&11=01或10&11=10,如果n为00则00&11=00,n为11则11&11=11,当与的结果为00或11时(十进制为0、3)返回False,其他返回True,并且要对n的二进制循环右移检查
  • 右移是指n的二进制这串数字往右移动
class Solution:
    def subsetXORSum(self, nums: List[int]) -> int:
        i, total = 0, 0  # 初始化计数器和总和变量
        #(1 << len(nums)) 将数字1左移len(nums)位,得到一个二进制数。对于长度为4的列表,即 (1 << 4),结果为16,表示列表的所有子集数量。
        while i < (1 << len(nums)):  # 外循环遍历所有可能的子集
            j = 0  # 初始化内循环的索引
            ans = 0  # 初始化当前子集的异或和
            while j < len(nums):  # 内循环遍历nums列表中的每个元素
            #例如,对于j=2,(1 << 2) 的结果是 4,二进制表示为 100。检查变量i的第j位是否为1
                if i & (1 << j):  # 检查当前子集中的位是否为1
                    ans ^= nums[j]  # 对当前子集的元素进行异或运算
                j += 1  # 增加内循环的索引
            total += ans  # 将当前子集的异或和累加到总和变量中
            i += 1  # 增加外循环的索引,继续下一个子集的计算
        return total  # 返回所有子集的异或和作为结果

371. 两整数之和(中)

  • 给你两个整数 a 和 b ,不使用 运算符 + 和 - ​​​​​​​,计算并返回两整数之和。

示例 1:

输入:a = 1, b = 2
输出:3

示例 2:

输入:a = 2, b = 3
输出:5

题解

  • 例子:

初始状态:
a = 2,二进制表示为 0010
b = 3,二进制表示为 0011
第一轮递归调用:
a ^ b = 0010 ^ 0011 = 0001
(a & b) << 1 = (0010 & 0011) << 1 = 0010 << 1 = 0100
递归调用 self.getSum(0001, 0100)。
第二轮递归调用:
a ^ b = 0001 ^ 0100 = 0101
(a & b) << 1 = (0001 & 0100) << 1 = 0000 << 1 = 0000
递归调用 self.getSum(0101, 0000)。
第三轮递归调用:
a ^ b = 0101 ^ 0000 = 0101
(a & b) << 1 = (0101 & 0000) << 1 = 0000 << 1 = 0000
递归调用 self.getSum(0101, 0000)。
此时,b等于0,满足终止条件,递归结束。
最终的结果为0101,即5。

class Solution:
    def getSum(self, a: int, b: int) -> int:
        # 如果b等于0,则不需要进位,直接返回a
        if b == 0:
            return a
        # 使用递归调用来计算和
        return self.getSum(a ^ b, (a & b) << 1)
  • 超出内存限制,由于python整数类型为无限长整数类型.我们需要将结果限制在32位范围内
class Solution:
    def getSum(self, a: int, b: int) -> int:
        MASK = 0xFFFFFFFF#由于 0xFFFFFFFF 的所有位都是1,与任何整数进行 & 操作都会保留该整数的低32位,并将高位清零
        # 如果b等于0,则不需要进位,直接返回a
        if b == 0:
            return a if a < 0x80000000 else ~(a ^ MASK)# 如果a小于0x80000000(负数的最高位为1),返回a;否则返回a和0xFFFFFFFF的按位异或取反结果
        # 使用递归调用来计算和
        return self.getSum((a ^ b)& MASK, ((a & b) << 1)& MASK)#通过 & 0xFFFFFFFF 将结果限制在32位范围内

面试题 05.01. 插入

  • 给定两个整型数字 N 与 M,以及表示比特位置的 i 与 j(i <= j,且从 0 位开始计算)。
    编写一种方法,使 M 对应的二进制数字插入 N 对应的二进制数字的第 i ~ j 位区域,不足之处用 0 补齐。

示例 1:

输入:N = 1024(10000000000), M = 19(10011), i = 2, j = 6
输出:N = 1100(10001001100)

示例 2:

输入: N = 0, M = 31(11111), i = 0, j = 4
输出:N = 31(11111)

题解

  • &:两位都为1时,结果为1;|:两位都为0时,结果为0
  • 1.先把N的i-j位置全部归0(与想归0的位置为0其他位为1的数&)
  • 2.把M塞进N(将M左移i位,与N位或|)
class Solution:
    def insertBits(self, N: int, M: int, i: int, j: int) -> int:
        for k in range(i,j+1):
            N &=~(1<<k)#~(1 << k) 的含义是将数字1左移k位,然后对其进行按位取反。这将生成一个二进制表示中只有第k位为0,其余位都为1的数。
        return N | (M<<i)
posted @ 2024-02-25 19:45  Frommoon  阅读(10)  评论(0编辑  收藏  举报