位运算:
在处理整形数值时,可以直接对组成整数的各个位进行操作,这意味这可以使用屏蔽技术获得整数中的各个位。
&与、|或、^异或、~非/取反、>>和<<运算符将二进制位进行右移或左移操作、
>>>将用0填充高位,>>用符号位填充高位,没有<<<运算符。
对于int类型,1<<35与1<<3是相同的,因为int类型通常是 32 位,35 % 32=3(实际上左移操作会先对位移的位数进行取模运算,取模的结果是实际有效的位移位数)。
问题:1~10这10个数,放在11个元素的数组中,有且只有一个重复数,每个元素只访问一次,不能开辅助空间,找出这个重复的。
解法:1、假如这11个数为 {1,2,3,4,5,6,6,7,8,9,10},将这11个数进行异或,结果是除重复数6外的所有数的异或值,相同数进行异或结果为0。然后在让结果在分别为1~10的数进行异或,结果就为重复数
2、我们也可以开一个int数组空间,用于存储每个数字出现的次数
public class Test1 {public static void main(String[] args) {
//1int n=11;int[] arr = new int[]{1,2,3,4,5,6,6,7,8,9,10};//题目所给数组//解答int result=0;for(int i=0;i<n;i++){result^=arr[i];}for(int i=1;i<n;i++){result^=i;}System.out.println(result);System.out.println("==============");//2//如果可以开辅助空间int[] helper = new int[n];for(int i=0;i<n;i++){helper[arr[i]]++;}for(int i=0;i<n;i++){if(helper[i]==2){System.out.println(i);break;}}}
}
问题:求某个数二进制位中1的个数
解法:把1逐次往左移,与运算,只要比对位不为1结果就为0:将该数减1,那么最低位的1会变为0,其后面低位的0会全部变为1,比如:1010 1000 -1=1010 0111,然后将俩者与运算就会把原数最低位的1消除掉,1010 1000 & 1010 0111 =1010 0000,不断减一,与运算直到原数为0。
public class Test3 {public static void main(String[] args) {int ans=0,m=9;while(m!=0){ans++;m&=(m-1);}System.out.println(ans);}
}
问题:判断某个数是否为2的整数次方。
解法:2的整数次方的二进制位表达中只有一个1. 用Test3中的算法,异或一次后结果为0即为2的整数次方
public class Test4 {public static void main(String[] args) {int n=8;int result= n&(n-1);if(result==0){System.out.println("是");}else {System.out.println("不是");}}
}
问题:将整数二进制位的奇偶位互换,比如: 9:1001 变换后为 6:0110
解法:将该数分别与 1010 .... 1010和 0101 .... 0101做与运算得到偶数位和奇数位,然后将偶数位右移一位,奇数位左移一位,在作异或 或者 或运算
public class Test5 {public static void main(String[] args) {int n=9;int ou=n& 0xaaaaaaaa; //1010 1010 1010....1010 用16进制表示为a..,算出偶数位// n位9时,ou为 0000 .... 1000int ji=n& 0x55555555; //0101 0101 0101....0101 算出奇数位//n为9时,ji为 0000 .... 0001System.out.println((ou >> 1) ^ (ji << 1));}
}
问题:给定double类型的 0~1的浮点数,打印它的二进制表达,如果无法用32位以内精确表达则打印ERROR,比如 0.625 打印 0.101
解法:小数转为二进制表达,乘2挪整。将小数部分乘2 ,看结果整数部分是否等于1,大于1就记下1,然后结果减1;小于1,就继续乘2;反复如此运算,直到结果为0。
public class Test6 {public static void main(String[] args) {double n =0.3; //0.625StringBuffer sb = new StringBuffer();sb.append("0.");while(n>0){//乘2挪整n*=2;//判断整数部分if(n>=1){sb.append("1");//消除整数部分n-=1;}else{sb.append("0");}}//这是按 题目中的32位是不包括 0. 的if(sb.length()>34){System.out.println("ERROR");}System.out.println(sb);}
}
问题:数组中只有一个数出现了一次,其他数都出现k次,找出只出现一次的数。
解法:首先我们需要知道,k个相同的k进制位数做不进位加法,结果为0,比如,2个相同的二进制数做不进位的加法结果为0.
所以我们需要做的就是把数组中的数转为k进制,然后做不进位加法,然后在转为10进制。
而Java中有方法Integer.toString(int[] arr,int k)帮助我们把数组arr中的元素转为k进制。
public class Test7 {public static void main(String[] args) {//需要用到把十进制与k进制互转int arr[] ={2,2,2,9,7,7,7,3,3,3,10,10,10,0,0,0};int len =arr.length;char[][] kRadix = new char[len][]; //存储的arr中元素的k进制表示的反转int k=3;//数组中最大元素转为k进制后的最大位数int maxLen=0;//转为k进制数for(int i=0;i<len;i++){//将arr中的元素转换为k进制,反转,在转为字符数组。 Integer.toString(arr[i],k)将int类型数转换位k进制的字符串//反转:是因为这里是转为字符串存储的,如果arr中元素的k进制位数不相同的话//比如:10 为 101 , 7为 21 ,转为字符串存储就位就对不齐了,应该是7中的2对应10中的0,字符串存储却是2对应第一个1了,所以反转保证低位对齐。kRadix[i]=new StringBuilder(Integer.toString(arr[i],k)).reverse().toString().toCharArray();if(kRadix[i].length>maxLen){maxLen=kRadix[i].length;}}//对每个数的每一位进行不进位加法运算int[] ans=new int[maxLen];for(int i=0;i<len;i++){//加法for(int j=0;j<maxLen;j++){if(j>=kRadix[i].length){ //kRadix[i].length即该元素k进制表达的位数,j大于:表示在j位上,该元素没有数,为0。ans[j]+=0;}else{ans[j]+=(kRadix[i][j]-'0');//该元素在j位上有值。 -'0'是把该数字从char类型转为int类型。}}}int result=0;for(int i=0;i<maxLen;i++){result+= (ans[i]%k) * (int)Math.pow(k,i);//ans[i]%k即我们要求的数字的k进制表达中的第i位数,然后乘上Math.pow(k,i)进制:k的i次方进制}System.out.println(result);}
}