位运算解题
位运算,就是对数字进行左移右移与或非等各种操作,来实现解题
介绍常用的位运算操作
- 4>>1 4右移一位就是2 ,因为在计算机中都是以二进制运算位移也一样
- 4 << 1 4左移一位就是8 ,
- ~4 对4进行取反 是-5,因为计算机中是用补码进行运算比如4的原码是00000100,则补码就是00000100,对补码进行取反则 11111011,因为要用原码进行显示则就是补码变原码,正常负数的补码变原码都是取反+1,我这里有个技巧就是,从右往左数遇到第一个1则其1的左侧全部取反,第一个1保持不变,右侧不变,,10000101,-5;
- ^ 这个标志是异或,异或就是异或1则取反,异或0则保持不变,这里有个小技巧就是相同数字异或是0,于0异或就是本身,于全1异或就是按位全部取反
- & 与,你可以把它看成乘法,10 == 0,11 = 1。逻辑规则上是这样,这里介绍一个关于 &的小技巧,x代表一个10进制数 (x-1)&x 能消去最低位的1。如何判断这个数是否为2的幂次方可以用(x-1)&x==0
- | 或 , 你可以看作+法 1+1 == 1 ,1+0 ==1, 0+0 ==0。
现在就开始运用理论来实践
题目
题目1,找出唯一的成对的数
题目:
在1-10这10个数放在含有11个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。,每个元素只能访问一次,不能使用辅助存储空间
解析:
- 题目:规定了每个元素只能访问一次,并且不能使用辅助空间。
- 这篇文章是以位移为主题所以用位移来写,按照我们前面的常用运算符思路,能够解决这个题目。
- 该题目是从1-10中放到长度为11的数组中,因为是1-10数值,必然是1-10其中的一个重复值。
下面用图片解释
代码:
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = {1,2,3,4,5,6,5,8,9,10,7};
int b = 0;
//下面这个功能就是拿1-10来异或数组中的1-10
for (int i =1; i <=10; i++) {
b= b^i;
}
for (int i = 0; i < a.length; i++) {
b = b^a[i];
}
System.out.println(b);
}
题目2: 二进制1的个数
题目:
请实现一个函数,输入一个整数,输出该数的二进制表示中1的个数
例如:9的二进制表示为1001,有2位是1
解析:
两个方法
- 一个用位移的方法 (x>>1)&1,来一位一位的判断
- 用(x-1)&x来找到最低位的1并且消掉
代码:
// 第一种方法位移
public static int weiyi(int n) {
int sum = 0;
while (n!=0) {
if (((n>>0)&1)==1) {
sum++;
}
n= n>>1;
}
return sum;
}
// 第二个方法与方法
public static int yu(int n) {
int sum = 0;
while (n != 0) {
n= (n-1)&n;
sum++;
}
return sum;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
System.out.println("打印输入的数的二进制形式"+Integer.toString(n,2));
System.out.println("位移的方法,1的个数为"+weiyi(n));
System.out.println("与的方法,1的个数为"+yu(n));
}
题目3:将整数的奇偶位置互换
题目:
将整数的奇偶位置互换,假如有9这个数字1001,互换后是0110;变成6了
解析:
- 先把原数字和010101010101进行与运算把所有的偶数位置给剥离出来
- 在把原数字和1010101010进行与运算把所有的奇数位置给剥离出来
- 偶数位置左移一位变成奇数上的值
- 奇数位置右移一位变成偶数上的值
- 把算出来的两个值异或一下就是奇偶位置互换的值了
代码:
自行完善,int型是32位
我这里暂时不写,过段时间有空更新在评论区
题目3:出现k次与出现一次
题目:
数组中有这样一个数出现1次,其他的数都出现了k次,请输出只出现一次的数
解析:
有这样一个规律 相同二进制进行2次按位不进位加法是等于0,相同10进制进行10次按位不进位加法是等于0
相同n进制进行n次按位的不进位加法是等于0
代码:
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = {2,2,8,2,7,3,7,3,7,3,10,10,10,100,100,100,0,0,0,12139999,12139999,12139999};
int k =3;
char[][] aStrings = new char[a.length][];
int maxlen =0;
for (int i =0;i<a.length; i++) {
aStrings[i] = Integer.toString(a[i],k).toCharArray();
if (aStrings[i].length>maxlen) {
maxlen = aStrings[i].length;
}
}
int[] b = new int[a.length]; // 用来存入运算结果按位来加
for (int i = 0; i <a.length; i++) {
for (int j= aStrings[i].length-1;j>=0;j--) {
b[j] += aStrings[i][j] - '0';
if (b[j] >= k) { //如果大于等于k说明要进位了则进行不进位加法,把进位去掉也就-k
b[j] -= k;
}
}
}
int ans=0;
for (int i = 0; i < b.length; i++) {
ans += b[i]*Math.pow(k, i); // 把k进制转换成10进制
}
System.out.println(ans);
}
文章内容来源和参考于 蓝桥学院《算法真美课程》郑未老师。
学好算法,走遍天下都不怕,仅此激励自己不断学习
描述有问题的,评论或者私聊我,我继续改成完善。