1.位运算
位运算符
- 在处理整形数值时,可以直接对组成整形数值的各个位进行操作。这意味着可以使用屏蔽技术获得整数中的各个位(? ? )
- &(与)、| (或)、^(异或)、~ (非/取反)
- ">>"和"<<"运算符将二进制位进行右移或者左移操作
- ">>>"运算符将用0填充高位; >>运算符用符号位填充高位,没有<<<运算符
- 对于int型,1<<35与1<<3是相同 的,而左边的操作数是long型时需对右侧操作数模64
- 与:都为1结果为1,或:有一个为1结果为1,异或:二者不同时结果为1
a | b | ~a | a&b | a|b | a^b |
---|---|---|---|---|---|
1 | 1 | 0 | 1 | 1 | 0 |
0 | 1 | 1 | 0 | 1 | 1 |
0 | 0 | 1 | 0 | 0 | 0 |
-
判断奇偶数 x&1=1为奇数 =0为偶数 原因:奇数最后一位是1,&1后为1,偶数最后一位为0,&1后为0
-
获取二进制位是1还是0 (两种解决方案)
86的二进制第5位是1还是0?
- 1先左移4位和86与运算,结果再右移,和为1则为,为0则为0
- 86右移4位,然后结果为和1与运算,结果1则为,为0则为0
86>>4&1
- 交换两个整数变量的值
int a=2,b=1;
a=a^b;
b=a^b;
a=a^b;
System.out.println("a=="+a+",b=="+b);
- 不用判断语句,求整数的绝对值
int a=-88;
System.out.println((a^a>>31)+(a>>>31));
结果:88
-
异或,可以理解为不进位加法:1 +1=0 , 0+0=0 , 1+0=1 .
性质
1、交换律可任意交换运算因子的位置,结果不变
2、结合律(即(a^b)^c == a^(b^c) )
3、对于任何数x ,都有x^x=0 , x^0=x,同自己求异或为0 ,同0求异或为自己
1 1 0 1
^1 1 0 1
————
0 0 0 0
4、自反性A^B^B=A^0=A ,连续和同一一个因子做异或运算,最终结果为自己
题1:找出唯一成对的数
1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
import java.util.Arrays;
import java.util.Random;
public class Main {
public static void main(String[] args) {
int N=11;
int[] arr=new int[N];
for (int i = 0; i <arr.length-1 ; i++) {
arr[i]=i+1;
}
arr[N-1]=new Random().nextInt(N-1)+1;
int index=new Random().nextInt(N);
int t;
t=arr[N-1];
arr[N-1]=arr[index];
arr[index]=t;
System.out.println(Arrays.toString(arr));
int x=0;
for (int i = 0; i <N-1 ; i++) {
x=x^(i+1);
}
for (int i = 0; i <N ; i++) {
x^=arr[i];
}
// x^x=0,出现两次的消去,剩下出现三次的
System.out.println(x);
// 辅助空间方法
int[] h=new int[N];
for (int i = 0; i <N ; i++) {
h[arr[i]]++;
}
for (int i = 0; i < N; i++) {
if(h[i]==2){
System.out.println(i);
}
}
}
}
题2:找出落单的那个数
一个数组里除了某一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。
题3:二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。
例: 9的二进制表示为1001,有2位是1
import java.util.Scanner;
public class _1的个数 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int N=sc.nextInt();
System.out.println(Integer.toString(N,2));
int count=0;
for (int i = 0; i < 32; i++) {
if((N&1<<i)==1<<i){
count++;
}
}
System.out.println(count);
// 另一种解法
count=0;
while(N!=0){
N=(N-1)&N;
count++;
}
System.out.println(count);
}
}
题4:是不是2的整数次方
用一条语句判断一个整数是不是2的整数次方。
if(((N-1)&N)==0){
System.out.println("yes");
}else{
System.out.println("no");
}
题5:将整数的二进制奇偶位互换
1&保留,0&置零,0^保留
public class _奇偶位交换 {
public static void main(String[] args) {
int a=6;
System.out.println(m(a));
//结果为9
}
private static int m(int i){
int ou=i&0xaaaaaaaa;//和1010 1010 ...做与运算得到偶位
int ji=i&0x55555555;//和0101 0101 ...做与运算得到奇位
return (ou>>1)^(ji<<1);
}
}
题6:0~1间浮点实数的二进制表示
- 给定一个介于0和1之间的实数, (如0.625) ,类型为double,打印它的二进制表示(0.101,因为小数点后的二进制分别表示0.5,0.25.0.12.....)。
- 如果该数字无法精确地用32位以内的-进制表示,则打印“ERROR”
public class _浮点数二进制表示 {
public static void main(String[] args) {
double m=0.625;
StringBuilder re=new StringBuilder("0.");
while(m>0){
m=m*2;//乘2:挪整
if(m>=1){//判断整数部分
re.append("1");
m=m-1;//消除整数部分
}else{
re.append("0");
}
}
if(re.length()>34){
System.out.println("ERROR");
return;
}
System.out.println(re);
}
}
题7:出现k次与出现1次
数组中只有-一个数出现了1次,其他的数都出现了k次,请输出只出现了1次的数。
2 个相同的2 进制数做不进位加法,结果为0
10个相同的10进制数做不进位加法,结果为0
k 个相同的k 进制数做不进位加法,结果为0
public class _07_出现K次 {
public static void main(String[] args) {
int[] arr = {2, 2, 2, 9, 7, 7, 7, 3, 3, 3, 6, 6, 6, 0, 0, 0};
int len = arr.length;
char[][] kRadix = new char[len][];
int k = 3;
int maxLen = 0;
//转成k进制字符数组
//对于每个数字
for (int i = 0; i < len; i++) {
//求每个数字的三进制字符串并翻转,然后转为字符数组
kRadix[i] = new StringBuilder(Integer.toString(arr[i], k)).reverse().toString().toCharArray();
if (kRadix[i].length > maxLen)
maxLen = kRadix[i].length;
}
//不进位加法
int[] resArr = new int[maxLen];
for (int i = 0; i < len; i++) {
// 不进位加法
for (int j = 0; j < maxLen; j++) {
if (j >= kRadix[i].length)
resArr[j] += 0;
else
resArr[j] += (kRadix[i][j] - '0');
}
}
int res = 0;
for (int i = 0; i < maxLen; i++) {
res += (resArr[i] % k) * (int) (Math.pow(k, i));// 8%3=2,
}
System.out.println(res);
}
}