java中的位运算技巧
一、位运算基础
1.1 基本运算符
int a = 5;
int b = 3;
System.out.println(a & b);
System.out.println(a | b);
System.out.println(a ^ b);
System.out.println(~a);
System.out.println(a << 2);
System.out.println(a >> 1);
System.out.println(-5 >>> 1);
1.2 运算符优先级
int result = 5 | 3 & 2;
int result2 = (5 | 3) & 2;
二、高频位运算技巧
2.1 奇偶判断
public static boolean isOdd(int n) {
return (n & 1) == 1;
}
System.out.println(-5 % 2);
System.out.println(-5 & 1);
2.2 交换两数(无需临时变量)
public static void swap(int a, int b) {
System.out.println("Before: a=" + a + ", b=" + b);
a ^= b;
b ^= a;
a ^= b;
System.out.println("After: a=" + a + ", b=" + b);
}
swap(5, 3);
int temp = a;
a = b;
b = temp;
2.3 判断是否为 2 的幂
public static boolean isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
System.out.println(isPowerOfTwo(8));
System.out.println(isPowerOfTwo(6));
System.out.println(isPowerOfTwo(0));
System.out.println(isPowerOfTwo(-4));
public static int roundUpToPowerOfTwo(int n) {
n--;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return n + 1;
}
roundUpToPowerOfTwo(10);
roundUpToPowerOfTwo(17);
2.4 获取最低位的 1
public static int getLowestBit(int n) {
return n & (-n);
}
System.out.println(getLowestBit(84));
System.out.println(getLowestBit(12));
System.out.println(getLowestBit(7));
class BIT {
private int[] tree;
public void update(int i, int delta) {
while (i < tree.length) {
tree[i] += delta;
i += (i & -i);
}
}
}
2.5 统计二进制中 1 的个数
public static int countBits1(int n) {
return Integer.bitCount(n);
}
public static int countBits2(int n) {
int count = 0;
while (n != 0) {
n &= (n - 1);
count++;
}
return count;
}
public static int countBits3(int n) {
int count = 0;
for (int i = 0; i < 32; i++) {
if ((n & (1 << i)) != 0) {
count++;
}
}
return count;
}
private static final int[] BIT_COUNT = new int[256];
static {
for (int i = 0; i < 256; i++) {
BIT_COUNT[i] = (i & 1) + BIT_COUNT[i >> 1];
}
}
public static int countBits4(int n) {
return BIT_COUNT[n & 0xFF] +
BIT_COUNT[(n >> 8) & 0xFF] +
BIT_COUNT[(n >> 16) & 0xFF] +
BIT_COUNT[(n >> 24) & 0xFF];
}
System.out.println(countBits2(15));
System.out.println(countBits2(7));
System.out.println(countBits2(0));
2.6 清除/设置/翻转指定位
public class BitManipulation {
public static int clearBit(int n, int i) {
int mask = ~(1 << i);
return n & mask;
}
public static int setBit(int n, int i) {
int mask = 1 << i;
return n | mask;
}
public static int toggleBit(int n, int i) {
int mask = 1 << i;
return n ^ mask;
}
public static boolean isBitSet(int n, int i) {
return ((n >> i) & 1) == 1;
}
public static int clearBitsRange(int n, int i, int j) {
int allOnes = ~0;
int left = allOnes << (j + 1);
int right = (1 << i) - 1;
int mask = left | right;
return n & mask;
}
}
int n = 0b1101;
System.out.println(Integer.toBinaryString(clearBit(n, 2)));
System.out.println(Integer.toBinaryString(setBit(n, 1)));
System.out.println(Integer.toBinaryString(toggleBit(n, 0)));
System.out.println(isBitSet(n, 2));
2.7 快速幂运算
public static long quickPow(int x, int n) {
long result = 1;
long base = x;
while (n > 0) {
if ((n & 1) == 1) {
result *= base;
}
base *= base;
n >>= 1;
}
return result;
}
System.out.println(quickPow(2, 10));
System.out.println(quickPow(3, 13));
三、实战应用场景
3.1 权限控制(位掩码)
public class Permission {
public static final int READ = 1 << 0;
public static final int WRITE = 1 << 1;
public static final int EXECUTE = 1 << 2;
public static final int DELETE = 1 << 3;
private int permissions = 0;
public void grant(int permission) {
permissions |= permission;
}
public void revoke(int permission) {
permissions &= ~permission;
}
public boolean hasPermission(int permission) {
return (permissions & permission) == permission;
}
public boolean hasAnyPermission(int... perms) {
for (int perm : perms) {
if ((permissions & perm) != 0) {
return true;
}
}
return false;
}
public boolean hasAllPermissions(int... perms) {
int combined = 0;
for (int perm : perms) {
combined |= perm;
}
return (permissions & combined) == combined;
}
public void toggle(int permission) {
permissions ^= permission;
}
public void clearAll() {
permissions = 0;
}
public String describe() {
StringBuilder sb = new StringBuilder();
if (hasPermission(READ)) sb.append("READ ");
if (hasPermission(WRITE)) sb.append("WRITE ");
if (hasPermission(EXECUTE)) sb.append("EXECUTE ");
if (hasPermission(DELETE)) sb.append("DELETE ");
return sb.toString().trim();
}
}
Permission user = new Permission();
user.grant(Permission.READ | Permission.WRITE);
System.out.println(user.describe());
System.out.println(user.hasPermission(Permission.READ));
System.out.println(user.hasPermission(Permission.DELETE));
user.revoke(Permission.WRITE);
System.out.println(user.describe());
user.toggle(Permission.EXECUTE);
System.out.println(user.describe());
3.2 状态压缩(棋盘游戏)
public class TicTacToe {
private int board = 0;
private static final int EMPTY = 0b00;
private static final int X = 0b01;
private static final int O = 0b10;
public void setCell(int pos, int player) {
int shift = pos * 2;
board &= ~(0b11 << shift);
board |= (player << shift);
}
public int getCell(int pos) {
int shift = pos * 2;
return (board >> shift) & 0b11;
}
public boolean checkWin(int player) {
int[][] lines = {
{0,1,2}, {3,4,5}, {6,7,8},
{0,3,6}, {1,4,7}, {2,5,8},
{0,4,8}, {2,4,6}
};
for (int[] line : lines) {
if (getCell(line[0]) == player &&
getCell(line[1]) == player &&
getCell(line[2]) == player) {
return true;
}
}
return false;
}
public void display() {
for (int i = 0; i < 9; i++) {
int cell = getCell(i);
System.out.print(cell == EMPTY ? "." :
cell == X ? "X" : "O");
if (i % 3 == 2) System.out.println();
}
}
}
TicTacToe game = new TicTacToe();
game.setCell(0, TicTacToe.X);
game.setCell(4, TicTacToe.X);
game.setCell(8, TicTacToe.X);
game.display();
System.out.println(game.checkWin(TicTacToe.X));
3.3 集合运算(布隆过滤器基础)
public class BitSet {
private long[] words;
private static final int BITS_PER_WORD = 64;
public BitSet(int size) {
words = new long[(size + BITS_PER_WORD - 1) / BITS_PER_WORD];
}
public void add(int num) {
int wordIndex = num / BITS_PER_WORD;
int bitIndex = num % BITS_PER_WORD;
words[wordIndex] |= (1L << bitIndex);
}
public void remove(int num) {
int wordIndex = num / BITS_PER_WORD;
int bitIndex = num % BITS_PER_WORD;
words[wordIndex] &= ~(1L << bitIndex);
}
public boolean contains(int num) {
int wordIndex = num / BITS_PER_WORD;
int bitIndex = num % BITS_PER_WORD;
return (words[wordIndex] & (1L << bitIndex)) != 0;
}
public BitSet union(BitSet other) {
BitSet result = new BitSet(words.length * BITS_PER_WORD);
for (int i = 0; i < words.length; i++) {
result.words[i] = this.words[i] | other.words[i];
}
return result;
}
public BitSet intersect(BitSet other) {
BitSet result = new BitSet(words.length * BITS_PER_WORD);
for (int i = 0; i < words.length; i++) {
result.words[i] = this.words[i] & other.words[i];
}
return result;
}
public BitSet difference(BitSet other) {
BitSet result = new BitSet(words.length * BITS_PER_WORD);
for (int i = 0; i < words.length; i++) {
result.words[i] = this.words[i] & ~other.words[i];
}
return result;
}
public int size() {
int count = 0;
for (long word : words) {
count += Long.bitCount(word);
}
return count;
}
}
BitSet set1 = new BitSet(100);
set1.add(1);
set1.add(3);
set1.add(5);
BitSet set2 = new BitSet(100);
set2.add(3);
set2.add(5);
set2.add(7);
BitSet union = set1.union(set2);
BitSet intersect = set1.intersect(set2);
BitSet diff = set1.difference(set2);
System.out.println(union.size());
System.out.println(intersect.size());
System.out.println(diff.size());
3.4 算法优化(LeetCode 高频)
public class BitAlgorithms {
public int singleNumber(int[] nums) {
int result = 0;
for (int num : nums) {
result ^= num;
}
return result;
}
public int singleNumber2(int[] nums) {
int twos = 0;
for (int num : nums) { ^ num) & ~twos;
twos = (twos ^ num) & ~ones;
}
return ones;
}
public int hammingWeight(int n) {
int count = 0;
while (n != 0) {
n &= (n - 1);
count++;
}
return count;
}
public int[] countBits(int n) {
int[] result = new int[n + 1];
for (int i = 1; i <= n; i++) {
result[i] = result[i >> 1] + (i & 1);
}
return result;
}
public int reverseBits(int n) {
int result = 0;
for (int i = 0; i < 32; i++) {
result = (result << 1) | (n & 1);
n >>= 1;
}
return result;
}
public int getSum(int a, int b) {
while (b != 0) {
int carry = (a & b) << 1;
a = a ^ b;
b = carry;
}
return a;
}
public int maxProduct(String[] words) {
int n = words.length;
int[] masks = new int[n];
for (int i = 0; i < n; i++) {
for (char c : words[i].toCharArray()) {
masks[i] |= 1 << (c - 'a');
}
}
int maxProd = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if ((masks[i] & masks[j]) == 0) {
maxProd = Math.max(maxProd,
words[i].length() * words[j].length());
}
}
}
return maxProd;
}
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
int n = nums.length;
for (int mask = 0; mask < (1 << n); mask++) {
List<Integer> subset = new ArrayList<>();
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0) {
subset.add(nums[i]);
}
}
result.add(subset);
}
return result;
}
}
BitAlgorithms algo = new BitAlgorithms();
System.out.println(algo.singleNumber(new int[]{4,1,2,1,2}));
System.out.println(algo.getSum(3, 5));
System.out.println(algo.subsets(new int[]{1,2,3}));
⬅️ super深层剖析 🏠 00-Java ➡️ 内部类
💬 评论