提到位运算大家都不陌生,可能很多人都只是了解一下,就在某些实训平台上做了几个题。比如我就是,刚开始学的时候就只在educoder照着模板抄了一下,样例通过了就放在一边了。直到昨天看了几个关于位运算的视频才发现原来还可以这样用,所以忍不住就来和大家分享一下。(第一次写,写得不好的请大家见谅。我也只是一个小白,写的不对的也希望大佬能够提醒我一下)
- 异或运算( ^ ) 参加运算的两个数据,按二进制位进行异或运算。该运算满足交换律和结合律。
运算规则:0^0=1; 0^1=1; 1^0=1;
比如9^5,9的二进制形式是00001001,5的二进制形式是00000101,二者的运算方式如下:
00001001
00000101
——————————
00001100 该数的十进制为12
题一:
解析:根据异或运算的运算规则,如果两个数相同,那么他们两个数进行异或运算(异或运算是通过二进制形式进行运算)得到的二进制都为0,转换为十进制也为0。如果我们把数组遍历进行异或运算,就会把那两个相同的数变成零。比如:假设该组数为1,2,1,3,依次进行异或运算得到1 ^ 2 ^ 1 ^ 3=1 ^ 1 ^ 2 ^ 3=0 ^ 2 ^ 3=2 ^ 3,这时如果我们把得到的结果在与去掉重复数的该组数进行异或运算就会得到2 ^ 3 ^ (1 ^ 2 ^ 3)=2 ^ 2 ^ 3 ^ 3 ^ 1=0 ^ 0 ^ 1 =1,就可以得到那个重复的数据了。利用异或运算的规则,将两个成对出现的数进行异或运算就会变成零,所以我们需要把原数组中重复出现两次的数变成奇数个,单个出现的数变成偶数个,再进行异或运算,这样就能把原来单个出现的数全部消掉变成0,只剩下原来那个出现两次的数。代码如下:
由于1-1000数据太多,不好观察结果,所以我就减少了数据的个数。
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr={1,2,3,4,5,6,1};
int x=0; //储存遍历异或的结果
for(int i=0;i<arr.length;i++) { //遍历异或
x=x^arr[i];
}
for(int i=1;i<=6;i++) { //二次遍历异或
x=x^i;
}
//最后的x就是结果
System.out.println(x);
}
}
结果如下图所示:
学完了这个,再给大家留一道比较简单的题
这个题就比上个题容易多了,大家自己思考吧。
2.与运算(&)参加运算的两个数据,按二进制位进行“与”运算。
运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1两位同时为“1”,结果才为“1”,否则为0
比如:3&5 3的二进制形式为0011,5的二进制形式为0101
0011
0101
——————
0001 十进制为1
题二:
解析:这道题可以通过与运算来解决。思路:因为只有1&1=1,所以我们可以将该整数二进制中的每一个数与1进行与运算(通过移位运算,使该数二进制形式下的每一个数与1进行与运算),得到结果为1的话就将1的个数加一,由于整数最多只有32位,所以进行32次循环就行。代码如下:
import java.io.IOException;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws IOException {
Scanner sc=new Scanner(System.in);
int a=sc.nextInt();
int n=0; //记录1的个数
for(int i=0;i<32;i++) {
if(((a>>>i)&1)==1) { //每次将数无符号向右移动一位
n++;
}
}
System.out.println(n);
}
}
输入输出的结果如图所示:
补充:移位运算
比如9的二进制形式为:
1001
0100 向右移动一位
这道题还有一种解法,这种解法不容易想到。如果将9减一,二进制下的减法与10进制下的都一样,只不过二进制下的不够减了借1变2,十进制下的是变十
1001
- 1
——————
1000 将该数与9进行与运算
1001
——————
1000 可以看出消掉了一个一,也就是说,每进行一次这样的操作就会去掉
一个一,当一全部消掉时,该数就变成了0,所以我们只需输出该数消
掉一个次数即可。
代码如下:
import java.io.IOException;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws IOException {
Scanner sc=new Scanner(System.in);
int a=sc.nextInt();
int n=0; //记录消掉1的次数
while(a!=0) { //循环结束时该数为0
a=(a-1)&a;
n++;
}
//输出循环的次数即可
System.out.println(n);
}
}
这道题说完了再给大家来一道题目,大家自己思考,很简单。
提示一下:一个数如果是2的整数次方,那他的二进制形式下只有一个1
今天我想说的就是这些了,当然我想说的也不只有这些,第一次写大佬勿喷,写的不对的或者不好的希望大家多多包涵,如果哪里不清楚或者有更好的想法可以给我留言,我们一起学习一起进步。(如果说你看过这些题或者知道这些解法也不要喷我,因为我还在学习中,只是想通过这种方式来提高一下自己)以上是我看的一些视频之后写的,如果你们感兴趣的话可以私信我。