目录
- 题目
- 位运算分为两类:
- 231. 2 的幂
- 342. 4的幂
- 191. 位1的个数
- 面试题 16.01. 交换数字(中)
- 136. 只出现一次的数字
- 461. 汉明距离
- 693. 交替位二进制数
- 1863. 找出所有子集的异或总和再求和
- 371. 两整数之和(中)
- 面试题 05.01. 插入
题目
位运算分为两类:
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)
标签:11,运算,示例,二进制,题解,int,异或,合集
From: https://www.cnblogs.com/lushuang55/p/18032309