百度百科位运算
含义 | Pascal语言 | C语言 | Java |
---|---|---|---|
按位与 | a and b | a & b | a & b |
按位或 | a or b | a | b | a | b |
按位异或 | a xor b | a ^ b | a ^ b |
按位取反 | not a | ~a | ~a |
左移 | a shl b | a << b | a << b |
带符号右移 | a shr b | a >> b | a >> b |
无符号右移 | / | / | a>>> b |
1.& 与运算
同为1则为1,其余为0:1&1=1 、1&0=0、0&0=0
奇淫巧计:
/*
* 该数与该数-1相与,即可消除最后一个1
* 例:9
* 1001
* &
* 1000
* -----
* 1000
* */
【题目】判断一个整数是不是2的整数次方
【思路】将该数字转换为2进制之后,只有一个位上有1,用与运算消除一个1,判断是否为0,为0则表示是2的整数次方。
public class 2的整数次方 {
/*
* 用一条语句判断一个整数是不是2的整数次方
* */
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
if((N&(N-1)) == 0) {
System.out.println("是");
}else {
System.out.println("不是");
}
}
}
【题目】输入一个整数,输出该数二进制表示中1的个数。
【思路】该数与该数-1相与,即可消除最后一个1,循环消除,统计消除了几次即可求得1的个数
public class N {
/*
* 输入一个整数,输出该数二进制表示中1的个数。
* */
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N =scanner.nextInt();
System.out.println(Integer.toString(N, 2));
int count = 0;
while(N!=0) {
N = N&(N-1);
count++;
}
System.out.println(count);
}
2.^异或运算
具有相加不进位的特点,可用于消除两个重复的数,1^1 = 0 、1^0=1 、0^0=0
【题目】一个数组里面除了某一个数字外,其余数字都出现了两次,请找出这个数。
【思路】利用异或运算的特点,所有数字异或,消除重复的数字,剩下的结果就是这个落单的数。
public class 找出落单的那个数 {
/*
* 一个数组里面除了某一个数字外,其余数字都出现了两次,请找出这个数。
*
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = new int[]{1,1,2,2,3,3,4,4,5,5,6};
int x = 0;
for (int i = 0; i < arr.length; i++) {
x = (x^arr[i]);
}
System.out.println(x);
}
}
【题目】把1-1000的数放入有1001个空间的数组中,但有一个是重复的,找出这个数
【思路】由于异或是消除重复的,我们可以构建重复的数,将1-1000 和数组相异或,即(1^2...^n^...^1000)^(1^2^...n^n^...1000),两个的会消除,里面会出现3个n,消除之后,即可得出n
public class 唯一成对的数 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int N = 1001;
int[] arr = new int[N];
//给数组赋值
for (int i = 0; i < arr.length-1; i++) {
arr[i] = i+1;
}
//给末尾的未赋值的元素赋随机数
arr[arr.length-1] = new Random().nextInt(N-1)+1;
//随机的地址和末尾地址值的交换
int index = new Random().nextInt(N);
swap(arr, index, arr.length-1);
for (int i : arr) {
System.out.print(i+" ");
}
int x = 0;
for (int i = 1; i <= N-1; i++) {
x = (x^i);
}
for (int i = 0; i < arr.length; i++) {
x = (x^arr[i]);
}
System.out.println("\n"+x);
}
public static void swap(int[] arr,int index,int index2) {
//数组元素交换
int t;
t = arr[index];
arr[index] = arr[index2];
arr[index2] = t;
}
综合题:
【题目】输出一个数的奇偶位互换后的数
【思路】
9 的奇偶位呼唤
1001
&
1010
-------------
A:1000 可留下偶数位的数
1001
&
0101
------------
B:0001 可留下奇数位的数
A向右移1位,B向左移1位,相异或,即可求出来互换后的数
0100
^
0010
-----------
0110
public class 交换奇偶位 {
/*
* 输出一个数的奇偶位互换后的数
* */
public static void main(String[] args) {
// TODO Auto-generated method stub
int N = 9;//1001
int a = (N&0xaaaaaaaa);//1010 1010 1010 1010...
int b = (N&0x55555555);//0101 0101 0101 0101...
System.out.println((a>>1)^(b<<1));
}
}
提高题:
【题目】数组中只有一个数出现了1次,其余的数都出现了K次,请输出出现了1次的数。
【思路】将所有的数转换成次数进制,每一位分别相加在一起,对次数取余,出现K次的余数为0,剩余的则是出现1次的数的K进制数,再用pow方法转成十进制,即可还原成该数。
public class 出现K次与出现1次 {
/*
* 数组中只有一个数出现了1次,其余的数都出现了K次,请输出出现了1次的数。
* */
public static int k(int[] arr , int N) {
int value = 0;
int maxlen = 0;
char[][] kradix = new char[arr.length][];
for (int i = 0; i < arr.length; i++) {
kradix[i] = new StringBuilder(Integer.toString(arr[i], N)).reverse().toString().toCharArray();
if (kradix[i].length>maxlen) {
maxlen = kradix[i].length;
}
}
int[] resAry = new int[maxlen];
//不进位加法,所有的数的同一位一块相加,大于的部分不用看,加0即可
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < maxlen; j++) {
if(j >= kradix[i].length)
//该位置是0
resAry[j]+=0;
else
//求该位置不进位加法转换成整型
resAry[j]+=(kradix[i][j] - '0');
}
}
for (int i = 0; i < maxlen; i++) {
/*
*
* 将所有的数一块加,最后对N取余即可得出该位的数
* */
value += (resAry[i]%N)*(int)(Math.pow(N, i));
}
return value;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int N = 5 , Tag=1;
int[] arr = new int[N*5+1];//5个重复的N次的数和一个不重复的数
for (int i = 0; i < arr.length-1; i+=N) {
for (int j = 1; j <= N; j++) {
arr[i+j-1] = Tag;
}
Tag++;
}
arr[arr.length-1] = Tag;
for (int i : arr) {
System.out.print(i+" ");
}
System.out.println("\n"+k(arr, N));
}
}