位运算相关题目
题目1 判断一个整数是不是2的幂
-
测试链接 : https://leetcode.cn/problems/power-of-two/
-
思路
- 2的幂形式为: 0001 0010 0100 1000 … 在每一位上只有一个1
- 当n>0时,用Brian Kernighan算法提取出n的最右侧的1, 若提取后的数与原数相等, 则n为2的幂
-
代码
-
public class Code01_PowerOfTwo { public static boolean isPowerOfTwo(int n) { return n > 0 && n == (n & -n); } }
-
题目2 判断一个整数是不是3的幂
-
测试链接 : https://leetcode.cn/problems/power-of-three/
-
思路
- 幂 > 0
- 若一个数为3的幂, 则它一定只有3这个质数因子
- int范围内最大的3的幂(7只含有3这个质数因子)%n,
- == 0(可以整除) : n为3的幂
- != 0(不能整除) : n不为3的幂
-
代码
-
public static boolean isPowerOfThree(int n) { // 1162261467是int型范围内,最大的3的幂,它是3的19次方 return n > 0 && 1162261467 % n == 0; }
-
题目3 返回大于等于n的最小的2的幂
-
思路
- 若n <= 0, 则为1
- 若n > 0
- 先将n减一, 防止该数就是n的整数倍时, 操作后进位, 返回的不是本身,而是大于本身的数
- 将减一后的数最左侧的1开始往右全部刷成1
- n+1 转为2的n次方
-
代码
-
public static final int near2power(int n) { if (n <= 0) { return 1; } n--;// 当n不是2的某次方,没什么影响; 当n是2的某次方,起到降位的作用, 防止返回更大的数而不是本身 // 以下代码, 将减一后的数最左侧的1开始往右全部刷成1 n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return n + 1;// +1后变成2的某次方 }
-
题目4 区间[left, right]内所有数字 & 的结果
-
测试链接 : https://leetcode.cn/problems/bitwise-and-of-numbers-range/
-
思路
- 找规律,发现right &( right - 1) 的结果就是消掉right最右侧的1, 若消掉后的值right’ > left , 说明中间还有值可以继续消掉最右侧的1
- 一直消1直至right’ < = left, 说明无1可消了, 返回right’
-
代码
-
public static int rangeBitwiseAnd(int left, int right) { while (left < right) {// 用于判断前面到哪里的1能够留下来 right -= right & -right;// 每一次和-1后的数相与,都会使结果消掉最右侧的1 // 若消掉后的结果> left 说明中间还有数可以继续让最右侧的1消掉 } return right; }
-
题目5 反转一个二进制的状态,不是0变1、1变0,是逆序。超自然版
-
测试链接 : https://leetcode.cn/problems/reverse-bits/
-
思路
- 运用位运算不断位移拼接,使用二路归并的思想,从局部反转达到整体反转的目的
-
代码
-
public static int reverseBits(int n) { // 1010101010101010 0101010101010101 // 保留前一位 保留后一位 // >>> 1 : 前一位右移 << 1 : 后一位左移 // |: 将前后的数或到一块, 达到逆转的效果 n = ((n & 0xaaaaaaaa) >>> 1) | ((n & 0x55555555) << 1);// 1v1(每两位倒序) n = ((n & 0xcccccccc) >>> 2) | ((n & 0x33333333) << 2);// 2v2(每四位倒序) n = ((n & 0xf0f0f0f0) >>> 4) | ((n & 0x0f0f0f0f) << 4);// 4v4(每8位倒序) n = ((n & 0xff00ff00) >>> 8) | ((n & 0x00ff00ff) << 8);// 8v8(每16倒序) n = (n >>> 16) | (n << 16);// 16v16(每32位倒序) return n; }
-
题目6 返回一个数二进制中有几个1。
-
测试链接 : https://leetcode.cn/problems/hamming-distance/
-
思路
- 二路归并, 每次选相邻两个作为整体, 先计算左侧的1, 再计算右侧的1
- 两侧的1相加, 自动将两位合并为一个占位为2倍的数
-
代码
-
// 返回n的二进制中有几个1 // 两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。 // 给你两个整数 x 和 y,计算并返回它们之间的汉明距离 public class Code06_CountOnesBinarySystem { public static int hammingDistance(int x, int y) { return cntOnes(x ^ y);// 统计一下异或后1的个数, 即两个数字对应二进制位不同的位置的数目。 } public static int cntOnes(int n) { // 1.统计两位中右侧的1 2.统计两位中左侧的1 3.相加 -> 每两位看做一体 // 0101 == 5 0011 == 3 00001111 == 0x0f0f // !!!&!!! n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);// 迁移为每2位统计一次1的个数 n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);// 迁移为每4位统计一次1的个数 n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);// 迁移为每8位统计一次1的个数 n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);// 迁移为每16位统计一次1的个数 n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);// 迁移为每32位统计一次1的个数 return n; } }
-