# 位运算

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

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

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
}
-->