蓝桥杯算法很美第一章 位运算的奇巧淫技

蓝桥杯算法很美第一章 位运算的奇巧淫技

前序准备:

1 基本的位运算符的使用:

运算符 运算 范例
<< 左移 3 << 2 = 12 --> 3*2*2=12
>> 右移 3 >> 1 = 1 --> 3/2=1
>>> 无符号右移 3 >>> 1 = 1 --> 3/2=1
& 与运算 6 & 3 = 2
| 或运算 6 | 3 = 7
^ 异或运算 6 ^ 3 = 5
~ 反码 ~6 = -7

2.Java中关于位运算的Integer类的方法:

1.任意进制转十进制

1.转为int型:

public static int parseInt(String s,int radix)throws NumberFormatException
System.out.println(Integer.parseInt("1111",2));//15

2.转为Integer型:

public static Integer valueOf(String s,int radix) throws NumberFormatException

2.十进制转二进制

public static String toBinaryString(int i)
System.out.println(Integer.toBinaryString(15));//"1111"

3.十进制转十六进制

public static String toHexString(int i)
System.out.println(Integer.toHexString(15));//"f"

4.十进制转任意进制

public static String toString(int i, int radix)
System.out.println(Integer.toString(10,3));//101

正文

1.异或性质(可以理解为不进位加法: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求异或为自己

​ 4.自反性A^B^B=A^0=A,连续和同一个因子做异或运算,最终结果为自己

2.利用异或的算法:

一.如何找数组中唯一成对的那个数:1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其他均出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助储存空间,能否设计一个算法实现?

思路:将1-1000所有数字先自己异或一遍,用变量存储,再用这变量与数组中的数字依次异或一遍。最后直接打印这个变量。
public static void main(String[] args) {
     
	int num[] = new int[1001];
	for(int i =0;i<1000;i++) {
     
		num[i]=i+1;
	}
	num[1000]=111;
	doubleNum(num);
}
public static void doubleNum(int num[]) {
     
	int a = 0;
	for(int i = 1;i<=num.length-1;i++) {
     
		a=a^i;
	}
	for(int i = 0;i<num.length;i++) {
     
		a=a^num[i];
	}
	System.out.println(a);
}

二.找出落单的那个数:一个数组里除了某一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。

public static void main(String[] args) {
     
	doubleNum(new int[]{
     1,1,2,2,3,3,4,5,5});
}
public static void doubleNum(int num[]) {
     
	int a = 0;
	for(int i = 0;i<num.length;i++) {
     
		a = a^num[i];
	}
	System.out.println(a);
}

3.其他

一.一题三解:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如:9的二进制表示为1001,有2位是1.

public static void main(String[] args) {
     
	countOne(15);
}
public static void countOne(int x) {
     
	int count = 0;
    //法一:
	for(int i =0;i<32;i++) {
     
		if((x&(1<<i))==1<<i) count++;
	}
	System.out.println(count);
	count=0;
    //法二:
	for(int i=0;i<32;i++) {
     
		if(((x>>>i)&1)==1) count++;			
	}
	System.out.println(count);
	count=0;
    //法三:
	while(x!=0) {
     
		x=(x&(x-1));
		count++;
	}
	System.out.println(count);
}
收获:x=(x&(x-1))可以消除最低位的1

二.将整数奇偶位互换

public static void main(String[] args) {
     
	System.out.println(jiou(16));
}
public static int jiou(int x) {
     
	int ou = x&0b10101010_10101010_10101010_10101010;
	int ji = x&0b01010101_01010101_01010101_01010101;
	return (ou>>1)+(ji<<1);
}

三.0~1间浮点实数的二进制表示。给定一个介于0和1之间的实数,(如0.625),类型为double,打印它的二进制表示(0.101,因为小数点后的二进制分别表示0.5,0.25,0.125……)如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”

public static void main(String[] args) {
     
	double num = 0.375;
	StringBuilder sb = new StringBuilder();
	sb.append("0.");
	while(num!=0) {
     
		num = num*2;
		if(num>=1) {
     
			sb.append("1");
			num = num-1;
		}else {
     
			sb.append("0");
		}
		if(sb.length()>34) {
     
			System.out.println("ERROR");
			return;
		}
	}
	System.out.println(sb);
}

四.数组中只有一个数出现了一次,其他的数都出现了K次,请输出出现了1次的数。

思路:K个数进行不进位相加,最后在其K进制下各个数位为0

public static void main(String[] args) {
     
	int arr[] = {
     2,2,2,9,7,7,7,3,3,3,6,6,6,0,0,0};
	char kRadix[][] = new char[arr.length][];
	int maxlen = 0;
	int k = 3;
	for (int i = 0; i < arr.length; i++) {
     
		kRadix[i]=new StringBuilder(Integer.toString(arr[i], k)).toString().toCharArray();
		if(maxlen<kRadix[i].length) maxlen=kRadix[i].length;
	}
	int s[] = new int[maxlen];
	for(int j =0;j<arr.length;j++) {
     
		for(int i=0;i<maxlen;i++) {
     
			if(i>=kRadix[j].length) break; 
			else s[i]+=kRadix[j][i]-'0';
		}
	}
	StringBuilder sb = new StringBuilder();
	for(int i=0;i<s.length;i++) {
     
		sb.append(s[i]%k);
	}
	System.out.println(sb);
	System.out.println(Integer.parseInt(sb.toString(), k));
}

你可能感兴趣的:(算法,java,算法)