位运算

Posted mgblogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了位运算相关的知识,希望对你有一定的参考价值。

位运算主要有以下几方式

  1. 位的提取(把每一位提取出来)
  2. 字符串匹配,感觉在位运算中使用字符串很好用
  3. 异或运算去重复,异或代替其他运算,总之异或很重要

一、常用的知识点

(1)位操作

| 与运算:与运算用来置位

& 并运算:并运算用来掩码,n&(-n)可以获得最低位的1

~取反:用的很少

^异或运算:异或运算通常用来去重复 a^a=0

>>> 逻辑右移:高位补0

>>算数右移:补符号位

<<算数左移:补0

(2)Java中常用库函数

Integer.bitCount(int i):统计1的位数

Integer.highestOneBit(int i):取得最高位的1的int值

Integer.lowestOneBit(int i):取得最低位的1的int值

Integer.toString(int i, int radix):int转成radix进制的String

Integer.parseInt(String s, int radix):String转成让radix进制的int

二、类型题

(1)位的提取

461. 汉明距离

使用&与>>>提取n中的每一位,当然也可以使用Integer.bitCount();

 

class Solution {
    public int hammingDistance(int x, int y) {
        int n = x^y;
        int count = 0;
        while(n!=0) {
            if((n&1) == 1) count++;
            n = n >>> 1;
        }
        return count;
    }
}

190. 颠倒二进制位

相比与1在位运算中多使用0更好,一串0比一串1更好用int来表示

public class Solution {
    // you need treat n as an unsigned value
    public int reverseBits(int n) {
        int ans = 0;
        for(int i = 1; i <= 32; i++) {
            ans = ans << 1;
            ans = ans | (n&1);
            n = n >>> 1;
        }
        return ans;
    }
}

(2)使用^去重复

136. 只出现一次的数字

位运算的题一般也有提示:不使用额外空间、线性复杂度

 

class Solution {
    public int singleNumber(int[] nums) {
        int ans = nums[0];
        for(int i = 1; i < nums.length; i++) {
             ans = ans^nums[i];
        }
        return ans;
    }
}

268. 缺失数字

这个题O(n)时间复杂度用位运算,O(logn)则使用二分法

class Solution {
    public int missingNumber(int[] nums) {
        int ans = 0;
        for(int i = 0; i < nums.length; i++) {
            ans = ans^i^nums[i];
        }
        return ans^nums.length;
    }
}

260. 只出现一次的数字 III

class Solution {
    public int[] singleNumber(int[] nums) {
        int diff = 0;
        for(int num : nums) {
            diff ^= num;
        }
        diff = Integer.lowestOneBit(diff);//提取最右边的一位1
        int[] ans = new int[2];
        for(int num : nums) {
            if((num&diff)==0) ans[0] ^= num;
            else ans[1] ^= num;
        }
        return ans;
    }
}

(3)异或代替其他运算

不用额外变量交换a与b

public class Test {
    public static void main(String[] args) {
        int a = 2;
        int b = 5;
        a = a^b;
        b = a^b;
        a = a^b;
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

不用+-算加减

371. 两整数之和

class Solution {
    public int getSum(int a, int b) {
        return b == 0 ? a : getSum(a^b,(a&b)<<1);
    }
}

(4)使用字符串匹配

231. 2的幂

字符串匹配虽然没有位运算性能好,但它简单啊

class Solution {
    public boolean isPowerOfTwo(int n) {
        return n>0 && Integer.toString(n,2).matches("0*10*");
    }
}

位运算

class Solution {
    public boolean isPowerOfTwo(int n) {
        if(n < 0) return false;
        return Integer.bitCount(n) == 1 ? true : false;
    }
}

342. 4的幂

位运算

class Solution {
    public boolean isPowerOfFour(int num) {
        return num>0&&Integer.bitCount(num)==1&&((num&0b01010101010101010101010101010101)!=0);
    }
}

字符串

public boolean isPowerOfFour(int num) {
    return Integer.toString(num, 4).matches("10*");
}

693. 交替位二进制数

class Solution {
    public boolean hasAlternatingBits(int n) {
        return Integer.toString(n,2).matches("1(01)*0?");
    }
}

476. 数字的补数

class Solution {
    public int findComplement(int num) {
        String s = Integer.toString(num,2);
        StringBuilder ans = new StringBuilder(s);
        for(int i = 0; i < ans.length(); i++) {
            if(ans.charAt(i) == ‘1‘) ans.setCharAt(i,‘0‘);
            else ans.setCharAt(i,‘1‘);
        }
        return Integer.parseInt(new String(ans),2);
    }
}

(5)用二进制的每一位充当字母的映射表

318. 最大单词长度乘积

class Solution {
    public int maxProduct(String[] words) {
        int[] meme = new int[words.length];
        for(int i = 0; i < words.length; i++) {
            for(int j = 0; j < words[i].length(); j++) {
                meme[i] = meme[i] | (1 << words[i].charAt(j) - ‘a‘);
            }
        }
        int ans = 0;
        for(int i = 0; i < words.length-1; i++) {
            for(int j = i+1; j < words.length; j++) {
                if((meme[i] & meme[j]) == 0) 
                    ans = Math.max(ans,words[i].length()*words[j].length());
            }
        }
        return ans;
    }
}

以上是关于位运算的主要内容,如果未能解决你的问题,请参考以下文章

编程思想:巧用位运算重构代码

基础位运算基本原理和应用

位运算相关

优雅代码05-从hashMap源码介绍位运算符

c语言位运算问题?

为啥 JSHint 反对位运算符?我应该如何表达这个代码?