位运算的介绍及其应用

315 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

程序中的所有数在计算中都是以二进制的形式存储的,位运算实际就是直接对整数在内存中的二进制位进行操作。由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。

运算规则

符号描述运算规则
&两个位都为1时,结果才为1
l两个位都为0时,结果才为0
^异或相异为1,相同为0
~取反0变1,1变0
<<左移各二进制全部左移若干位,高位丢弃,低位补0,a<<b,表示a左移b位;
>>右移各二进制全部右移若干位,对于无符号数,高位补0,低位丢弃

ps:这里用 | 表示或显示不出来,就用字母l代替了...

XOR 异或

异或:相同为0,相异为1。

几个特点:

运算解释
x ^ 0 = xx中的每个0与0异或结果是0,每个1与0异或结果是1,所以x和0异或的结果依旧是x本身
x ^ x = 0x与自己本身做异或,表示每一个位异或的对象都是相同的值,相同值异或的结果当然是0
x^1s = ~x // 1s=~0x中的每个0与1异或结果是1,每个1与1异或结果是0,所以相当于是将x的每一位都取反了,即等于~x
x^(~x) = 1sx异或取反的x,表示每一位的异或都是不同的值,即结果返回1s
a^b=c => a^c=b, b^c=a异或满足交换律,从前面的例子中也可以得出该结论
a^b^c=a^(b^c)=(a^b)^c满足结合律

注:1s 表示多个位的1,s是x位的长度

实战中常用的位运算

1. x&1=1,表示x是奇数。

解释:x与1进行与运算,相当于是把x的最后一位跟1做与运算,因为x的高位跟1相与结果都是0,那么只要看x的最低位是0还是1就可以了,以下面为例。

  • 2&1 ==> 0010 & 0001 = 0000
  • 6&1 ==> 0110 & 0001 = 0000
  • 3&1 ==> 0011 & 0001 = 0001
  • 7&1 ==> 0111 & 0001 = 0001

可以看到高位的相与都是0,是没意义的,只要看最后一位与的结果就可以知道奇偶性了。奇数的最后一位必是1

2. x&(x-1) 可以清除x最低位的1

解释:

  • 10 & 9 ==> 1010 & 1001 = 1000

3. x&-x 可以得到最低为的1

解释:-x可以理解为对x取反再加1,即等于~x + 1。

应用

  • 权限判断
  • 字符串包含判断

权限判断

略。

字符串包含判断

题目:剑指 Offer II 005. 单词长度的最大乘积

给定一个字符串数组 words,请计算当两个字符串 words[i] 和 words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0。

示例:

输入: words = ["abcw","baz","foo","bar","fxyz","abcdef"]

输出: 16

解释: 这两个单词为 "abcw", "fxyz"。它们不包含相同字符,且长度的乘积最大。

根据题意,需要判断两个单词是否包含相同的字符,可通过位掩码进行判断。设mask[i] 为第i个单词的位掩码,那么当两者有相同字符时,那么 mask[i] & mask[j] == mask[j] 。两个相同字符相与,也即相同值相与肯定是他们本身。反过来想,若没有相同字符,每个位都不同,那么相与的结果就是0。

如何将字符改为位运算相与呢?我们可以通过将字符转换为二进制码,放到mask数组中。然后用mask数组进行与运算判断长度乘积即可。

class Solution {
    public int maxProduct(String[] words) {
        int max = 0;
        int[] mask = new int[words.length];
        for(int i=0;i<words.length;i++) {
            int n = words[i].length();
            for(int j=0;j<n;j++) {
                mask[i] |= 1<<(words[i].charAt(j) - 'a');
            }
        }

        for(int i=0;i<words.length;i++) {
            for(int j=i+1;j<words.length;j++) {
                if( (mask[i] & mask[j]) == 0) {    // 无交集
                    max = Math.max(max,words[i].length() *  words[j].length());
                }
            }
        }
        return max;
    }
}