# 位运算
func bitOperV1() { | |
var a uint8 = 60 /* 60 = 0011 1100 */ | |
var b uint8 = 13 /* 13 = 0000 1101 */ | |
var c uint8 = 0 | |
var ab byte = 0b00111100 // 二进制 | |
var ax byte = 0x3C // 十六进制 | |
var ao byte = 0o74 // 八进制 | |
fmt.Printf("a == ab: %v\n", a == ab) | |
fmt.Printf("a == ax: %v\n", a == ax) | |
fmt.Printf("a == ao: %v\n", a == ao) | |
c = a & b /* 12 = 0000 1100 */ | |
fmt.Printf("第一行 - c 的值为 %d \t二进制: %b\n", c, c) | |
c = a | b /* 61 = 0011 1101 */ | |
fmt.Printf("第二行 - c 的值为 %d \t二进制: %b\n", c, c) | |
c = a ^ b /* 49 = 0011 0001 */ | |
fmt.Printf("第三行 - c 的值为 %d \t二进制: %b\n", c, c) | |
c = a << 2 /* 240 = 1111 0000 */ | |
fmt.Printf("第四行 - c 的值为 %d \t二进制: %b\n", c, c) | |
c = a >> 2 /* 15 = 0000 1111 */ | |
fmt.Printf("第五行 - c 的值为 %d \t二进制: %b\n", c, c) | |
} |
a == ab: true | |
a == ax: true | |
a == ao: true | |
第一行 - c 的值为 12 二进制: 1100 | |
第二行 - c 的值为 61 二进制: 111101 | |
第三行 - c 的值为 49 二进制: 110001 | |
第四行 - c 的值为 240 二进制: 11110000 | |
第五行 - c 的值为 15 二进制: 1111 |
# 算法题
# 1. 位 1 的个数
https://leetcode.cn/problems/number-of-1-bits/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/11_BitOperations/level_2/topic_1.go
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数
func hammingWeight(num uint32) int { | |
ans := 0 | |
for num > 0 { | |
num = num & (num - 1) | |
ans++ | |
} | |
return ans | |
} |
# 2. 比特位计数
https://leetcode.cn/problems/counting-bits/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/11_BitOperations/level_2/topic_2.go
给你一个整数
n
,对于0 <= i <= n
中的每个i
,计算其二进制表示中1
的个数 ,返回一个长度为n + 1
的数组ans
作为答案。
func countBits(n int) []int { | |
dp := make([]int, n+1) | |
highBit := 0 | |
for i := 1; i <= n; i++ { | |
if i&(i-1) == 0 { | |
highBit = i | |
} | |
dp[i] = dp[i-highBit] + 1 | |
} | |
return dp | |
} |
# 3. 颠倒二进制位
https://leetcode.cn/problems/reverse-bits/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/11_BitOperations/level_2/topic_3.go
颠倒给定的 32 位无符号整数的二进制位。
// 将整数 n 向右移动一位并与 m1 进行按位与操作,然后将结果与 n 向左移动一位并与 m1 进行按位与操作的结果进行按位或操作。这一步交换了相邻的位。 | |
// 将上一步的结果向右移动两位并与 m2 进行按位与操作,然后将结果与上一步的结果向左移动两位并与 m2 进行按位与操作的结果进行按位或操作。这一步交换了每两位的块。 | |
// 将上一步的结果向右移动四位并与 m4 进行按位与操作,然后将结果与上一步的结果向左移动四位并与 m4 进行按位与操作的结果进行按位或操作。这一步交换了每四位的块。 | |
// 将上一步的结果向右移动八位并与 m8 进行按位与操作,然后将结果与上一步的结果向左移动八位并与 m8 进行按位与操作的结果进行按位或操作。这一步交换了每八位的块。 | |
// 将上一步的结果向右移动 16 位,并将结果与上一步的结果向左移动 16 位的结果进行按位或操作,完成整个整数的二进制位颠倒。 | |
const ( | |
m1 = 0b01010101010101010101010101010101 | |
m2 = 0b00110011001100110011001100110011 | |
m4 = 0b00001111000011110000111100001111 | |
m8 = 0b00000000111111110000000011111111 | |
) | |
func reverseBits(num uint32) uint32 { | |
num = num>>1&m1 | num&m1<<1 | |
num = num>>2&m2 | num&m2<<2 | |
num = num>>4&m4 | num&m4<<4 | |
num = num>>8&m8 | num&m8<<8 | |
return num>>16 | num<<16 | |
} |
# 4. 两整数之和
https://leetcode.cn/problems/sum-of-two-integers/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/11_BitOperations/level_2/topic_4.go
给你两个整数
a
和b
,不使用 运算符+
和-
,计算并返回两整数之和。
func getSum(a int, b int) int { | |
for b != 0 { | |
carry := uint(a&b) << 1 | |
a = a ^ b | |
b = int(carry) | |
} | |
return a | |
} |
# 5. 递归乘法
https://leetcode.cn/problems/recursive-mulitply-lcci/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/11_BitOperations/level_2/topic_5.go
递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。
func multiply(A, B int) int { | |
ans := 0 | |
// A == min | |
if A > B { | |
A, B = B, A | |
} | |
for i := 0; A > 0; i++ { | |
if (A & 1) == 1 { | |
ans += B << i | |
} | |
A >>= 1 | |
} | |
return ans | |
} |