蓝桥杯之位运算

相关用法

相关习题

习题一

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

public class _唯一成对的值 {
	public static void main(String[] args) {
		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;
		System.out.println(Arrays.toString(arr));
		
		int x = 0;//异或运算用,任何数和0异或都等于它本身,任何数和它本身异或都为0
		for (int i = 0; i < arr.length-1; i++) {
			if((arr[i]^arr[N-1]) == 0) { //异或优先级比较低,一般需要用括号括起来
				System.out.println("重复值是:"+arr[i]);
			}
		}
	}
}

习题二

找出落单的那个数
一个数组里除了某一个数字之外,其他的数字都出现了两次。请写出程序找出这个只出现一次的数字。
这道题用异或,凡是成对异或的数最后变为0消掉,剩下的数就是落单的数。例如x=A ^ B ^ C ^ B ^ A,最后x=C。

public class _找出落单的那个数 {

	public static void main(String[] args) {
		int[] arr = {3,4,1,4,5,3,1};
		int x = 0;
		for (int i = 0; i < arr.length; i++) {
			x = x^arr[i];
		}
		System.out.println("落单的数是:"+x);
	}
}
//落单的数是:5

习题三

二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例:9的二进制是1001,有2个1。
基本思想是每次将1往左移一位就与原来的数进行与运算,结果与1移位后相等就计数。

public class _二进制中1的个数 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int k = sc.nextInt();
		int count = 0;
		String kb = Integer.toBinaryString(k);
		System.out.println(k+"的二进制形式:"+kb);
		for (int i = 0; i < kb.length(); i++) {
			if((k&(1<<i)) == (1<<i))
				count++;
		}
		System.out.println("1的个数:"+count);
	}
}

从另外的思考角度想,当一个数(N-1)&N时,它的结果是会消掉从右数起的第一个1,例如整数104的二进制数1101000,减去1,变成1100111,与运算后变为1100000,可见右边的第一个1已经被消去。利用这种特性,可写处另外一种解法:

public class _二进制中1的个数 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int k = sc.nextInt();
		int count = 0;
		String kb = Integer.toBinaryString(k);
		System.out.println(k+"的二进制形式:"+kb);
		while(k!=0) {
			k=(k-1)&k;
			count++;
		}
		System.out.println("1的个数:"+count);
	}
}
/*
54
54的二进制形式:110110
1的个数:4
*/

习题四

用一条语句判断一个整数是不是2的整数次方。
经过上一道题,可以很简单的解答这道题。当一个数是2的整数次方时,它的二进制数中只有一个1。因此有:

public class _判断是否是2的整数次方 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int k = sc.nextInt();
		if(((k-1)&k) == 0)
			System.out.println("是");
		else
			System.out.println("否");
	}
}

习题五

交换奇数位和偶数位。例如10010110交换后变为01101001,值从150变为105。
具体实现是先保留出偶数位,奇数位消为0,在保留出奇数位,偶数位消为0。然后偶数位向右移动,奇数位向左移动,错位之后做异或运算。由于错位之后,偶数位和奇数位的每一位都是和0做异或,结果还是该位的值本身,所以结果就相当于偶数位和奇数位交换了位置。

public class _交换奇偶位 {
	public static void main(String[] args) {
		int a = 150;
		int b = exc(a);
		System.out.println(b);
	}

	private static int exc(int a) {
		int ou = a&0xaaaaaaaa;//0xaaaaaaaa是十六进制的1010 1010 1010...共32位,与运算可以保留二进制数的偶数位
		int ji = a&0x55555555;//0x55555555是十六进制的0101 0101 0101...共32位,与运算可以保留二进制数的寄数位
		return (ou>>1)^(ji<<1);//偶数位右移一位,奇数位左移一位,再异或
	}
}
//105

习题六

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

public class _转二进制小数 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		double num = sc.nextDouble();
		StringBuilder sb = new StringBuilder("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");
		}
		System.out.println(sb);
	}
}
/*0.625
0.101
*/

习题七

出现k次与出现1次
数组中只有一个数出现了1次,其他的数都出现了k次,请输出只出现了1次的数。
利用一下知识:
2位二进制的数字做不进位加法,结果为0
10个十进制的数字做不进位加法,结果为0
k个k进制的数字做不进位加法,结果为0
另外,n个k进制的数做不进位加法时,每一位上的数字是对应位数的和模k的结果。
解法:以k=3为例
1.定义一个数组存放一组数据
2.定义一个二维数组,每个元素是每一个数转换为3进制后再转换成字符串反转再变为字符数组
(这里反转是因为数字变为3进制后的位数并不一致,为了方便比较,反转后位数比较少的可以再后面添0而不影响大小)
3.找出位数最多的是几位
4.遍历二维数组的行和列,行位数不够的添0,然后每一列上的数字相加,存放在另一个新的数组resArr中
5.如果一个数出现3次后,它模3的结果为0.因此遍历数组reaAll,让每一个数模3,结果不是0的就是要找的那个数

public class _出现k次与出现1{
	public static void main(String[] args) {
		int[] arr = {2,2,2,29,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;
		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]%3)*(int)(Math.pow(k, i)); //相当于做不进位加法后,把数字转为10进制
		}
		System.out.println(res);
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值