(Java)算法——位运算在算法题中的应用
作者:互联网
位运算在算法题中的应用
上篇博客总结的位运算的基础和基本的使用,这篇博客总结一下位运算在一些算法题中的使用
上篇博客:位运算基础及基本应用
题1
数组1-1000中(1001个数),有唯一一个重复的数,其他数只出现一次,求唯一一个重复的数。
要求:数组元素只能访问一次,不使用辅助空间
解题思路
利用位运算的异或性质解题a ^ b ^ b = a ^ 0 = a。原数组1-1000并且有一个重复的数(数组长度1001),与数组1-1000进行所有元素异或,最后剩下的是唯一重复的数,其余的数都已经抵消。
代码实现
private static int findRepetitionNum ( int[] arr ) {
int x = 0;
//将1-1000进行运算,得出结果
for (int i = 1; i < arr.length; i++) {
x = (x ^ i );
}
//将x(将1-1000进行运算的结果)和目标数组(1-1000,并且包含一个重复的数)进行^运算
//前后抵消,只剩下那个重复的数
for (int i = 0; i <arr.length; i++) {
x = x ^ arr[i];
}
return x;
}
暴力破解(不符合要求,多用了一个辅助空间,数组)
解题思路
利用一个辅助数组,遍历原数组,值为辅助数组的索引,没出现一次+1,最后辅助数组中有一个索引的值为2,其索引为重复的数
代码实现
private static int findRepetitionNumByViolence(int[] arr){
int[] help=new int[arr.length];
for (int i = 0; i <help.length ; i++) {
help[arr[i]]++;
}
for (int i = 0; i <help.length ; i++) {
if (help[i]==2){
return i;
}
}
return 0;
}
题2
在一个值均成对,只有一个单独存在的数组中,找出单独存在的数
解题思路
利用异或的性质,数组所有元素进行异或,剩下的是单一的数。(和题1非常类似)
代码实现
private static int findOnlyNum ( int[] arr ){
for (int i = 1; i <arr.length; i++) {
arr[i] = arr[i] ^ arr[i-1] ;
if (i==arr.length-1){
return arr[i];
}
}
return 0;
}
题3
输入一个整数,输出该二进制表示中1的个数
实现方式1
解题思路
将1每次左移1位,判断整数每次左移的&运算,如果为1则+1
代码实现
private static int sumOneCount ( int n ) {
int count = 0;
//整数共32位
for (int i = 0; i < 32; i++) {
if ((n & (1 << i)) == (1 << i)) {
count++;
}
}
return count;
}
实现方式2
解题思路
将整数每次右移1位,进行&运算,如果为1则+1
代码实现
private static int sumOneCount ( int n ) {
int count = 0;
//整数共32位
for (int i = 0; i < 32; i++) {
if (((n >>> i)&1) == 1) {
count++;
}
}
return count;
}
实现方式3
解题思路
每次进行-1操作,从低位到高位遇到的第一个1变0,其余0变1
例如 10100 -1 -> 10011
(n - 1) & n,削掉最低位的1
例如 (10100-1)&10100 -> 100000
每循环一次,销掉一个1,次数+1,直至变为0.结束
代码实现
private static int sumOneCount ( int n ) {
int count = 0;
while (n != 0) {
n = ((n - 1) & n);
count++;
}
return count;
}
题4
交换一个整数的二进制奇偶位
解题思路
假设一个数n的二进制为 xyxy xyxy xyxy ……
- 和 1010 1010 1010 …… 做与运算,取出偶数位 ——>x0x0 x0x0 x0x0 ……
- 和 0101 0101 0101 …… 做与运算,取出奇数位 ——>0y0y 0y0y 0y0y ……
- 偶数位右移1位,奇数位左移1位,进行异或,交换位置——>yxyx yxyx yxyx ……
代码实现
private static int transform ( int n ) {
//假设n, xyxy xyxy xyxy ……
//32位太麻烦,所以用16进制来表示
//和 1010 1010 1010 …… 做与运算,取出偶数位 ——>x0x0 x0x0 x0x0 ……
int ou = n & 0xaaaaaaaa;
//和 0101 0101 0101 …… 做与运算,取出奇数位 ——>0y0y 0y0y 0y0y ……
int ji = n & 0x55555555;
//连起来为 yxyx yxyx yxyx ……
return (ou >> 1) ^ (ji << 1);
}
题5
整数是不是2的整数次方
要求:用一条语句判断
解题思路(和题3的方法3类似)
规律:整数是2的整数次方的数,二进制只有一个1
如果可以一次消除1之后变为0,说明是2的整数次方
代码实现
public static boolean isTwoNum(int n){
return ((n-1)&n)==0;
}
题6
0-1间浮点实数的二进制表示。
给定一个0-1间的实数,例如0.625,类型为double,打印二进制表示为(0.101,因为小数点后的二进制分别为0.5,0.25.0.125……)
如果该数字无法精确地用32位以内的二进制表示,则打印"ERROR"
解题思路
0-1间浮点实数的二进制计算方法:**每次乘2,扣除整数,直至变为0;**若大于32位则报错
代码实现
private static String transform(double n){
StringBuilder sb=new StringBuilder("0.");
while (n>0){
//每次乘2
double r=n*2;
//判断取的整数位是0还是1
if (r>=1){
sb.append("1");
n=r-1;
}else{
sb.append("0");
n=r;
}
//若大于32位则报错;34 包括 “0”和“.”
if (sb.length()>34){
return "ERROR";
}
}
return sb.toString();
}
题7
出现k次和1次
数组中只有一个数出现了1次,其他数都出现了k次
输出只出现一次的数
实现方式1_位运算
解题思路
2个相同的二进制数不进位相加等于0
10个相同的十进制数不进位相加等于0
k个相同的K进制数不进位相加等于0
代码实现
private static int findOneNum ( int[] arr, int k ) {
int len = arr.length;
//存每个数组元素的k进制的每一位
char[][] kRadix = new char[len][];
//数字中转成k进制最长的长度
int maxLen = 0;
//遍历每个数字
for (int i = 0; i < len; i++) {
//求每个数字的k进制并反转,然后转为字符数组;
// 反转——从低位进行不进位加法,保证位对齐
kRadix[i] = new StringBuffer(Integer.toString(arr[i], k)).reverse().toString().toCharArray();
//记录数字中转成k进制最长的长度
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 {
//char-'0'——char转为int类型
resArr[j] += (kRadix[i][j] - '0');
}
}
}
//将出现一次的数从k进制转为10进制
int res = 0;
for (int i = 0; i < maxLen; i++) {
//(int)(Math.pow(k,i))——k的i次方
res += (resArr[i]% k) * (int) (Math.pow(k, i));
}
return res;
}
实现方式1_哈希表
解题思路
利用哈希表,Java中的map存取<K,V>键值对,K为
数组的元素(不重复),V为该元素在数组中出现的次数。输出值为1的键,即是出现1次的数
代码实现
private static int findOneNum2 ( int[] arr ) {
Map<Integer, Integer> arrMap = new HashMap<>();
for (int value : arr) {
if (arrMap.containsKey(value)) {
arrMap.put(value, arrMap.get(value) + 1);
} else {
arrMap.put(value, 1);
}
}
for (Map.Entry<Integer, Integer> entry : arrMap.entrySet()) {
if (entry.getValue() == 1) {
return entry.getKey();
}
}
return 0;
}
这篇博客主要总结了一下,位运算在算法中的一些题解,下一篇总结下,利用位运算如何实现加减乘除?
标签:arr,Java,运算,题中,int,算法,解题,static,数组 来源: https://blog.csdn.net/qq_42937522/article/details/104664642