准备蓝桥杯之路(三) ------ 位运算的奇淫技艺2
前言
果然刚开始坚持某件事情就会有很多的阻碍扑面而来,刚从外地回到家事情实在是太多了,更别说还有各种突发情况(断水断电,害,说多了都是泪555555),不过我肯定会继续加油,坚持更新下去的。同时也希望能够帮助到有需要的同学。
这篇文章是对上篇文章(位运算的奇淫技艺)的一个补充和总结,如果想从头开始看的,我把上篇文章的链接粘到下面,大家直接去看就好。
上篇文章链接: 准备蓝桥杯之路(二) ------ 位运算的奇淫技艺
我是跟着哔哩哔哩的一个课程进行学习的,毕竟不是原创,所以下面我附上视频链接。
视频链接: 蓝桥杯零基础入门到比赛(二)——算法很美
习题
1. 出现k次与出现1次的数
题意描述: 数组中只有一个数出现了1次 其他数都出现了k次 请找出这个出现1次的数。
解题关键: 这道题的关键还是用某种技巧把数组中出现k次的数消掉,并且保留出现1次的那个数,这样问题就迎刃而解了。
注意这样的一个现象:10个相同的10进制数进行"不进位加法"操作之后的结果是0(eg: 如果10个3正常相加结果是30,3是那个进位,所以如果不进位的话,3就会被舍去,不进位加法的结果就是0),同理,2个相同的2进制数进行"不进位加法"操作之后的结果是0,k个相同的k进制数进行"不进位加法"操作之后的结果也是0。
到此,大致思路就理清了,具体过程看下面的代码实现。注: java中Integer.toString(i, radix)方法可以将十进制数转任意进制,并返回一个String对象。
代码实现
public class question_8 {
public static void main(String[] args){
int[] arr = {2, 2, 2, 9, 7, 7, 7, 3, 3, 3, 6, 6, 6, 0, 0, 0};
/**
* 解题关键: 2个相同的2进制数做不进位加法结果为0
* 10个相同的10进制数做不进位加法结果为0
* k个相同的k进制数做不进位加法结果为0
*/
int len = arr.length; //获取数组总长度
char[][] kRadix = new char[len][]; //创建一个二维数组用来存储对应数字的k进制表示
int k = 3; //k表示进制数
int maxLen = 0; // 数字k进制表示的最大字符串长度
//将数组中的各元素转为k进制表示
for(int i = 0; i < len; i++){
//反转之后实现从低到高表示k进制表示是为了各个位置对齐
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];
//实现k进制的不进位加法,并将所有数按位加起来
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; //计算最后的结果
//将最后的结果从k进制表示转化位10进制表示
for(int i = 0; i < maxLen; i++){
res += (resArr[i] % k) * (int)(Math.pow(k, i));
}
System.out.println("落单的那个数是" + res);
}
}
2. 0~1间浮点实数的二进制表示
题意描述: 给定一个介于0和1之间的实数,(如0.625),类型为double,打印它的二进制表示(0.101),如果该数字无法精确地用32位以内(小数点后32位)的二进制表示,则印"ERROR"。
解题关键: 该题没有特殊的技巧,掌握0~1间浮点实数的二进制表示和计算方法即可。
具体的计算方法不在此赘述,实在不懂的童鞋可以参考一下我在了知乎上找的这篇文章,文章链接如下:浮点数的二进制表示以及几个例子
代码实现
import java.util.Scanner;
public class question_6
{
public static void main(String[] args)
{
double num = 0.625;
StringBuilder sb = new StringBuilder("0.");
while(num > 0){
// num * 2 如果大于1补1,小于1补0。
double r = num * 2;
if(r >= 1){
sb.append("1");
num = r - 1;
}else{
sb.append("0");
num = r;
}
//如果32位之内不能表示,就跳出循环,并提示ERROR。
if(sb.length() > 34){
System.out.println("ERROR");
return;
}
}
System.out.println(sb);
}
}
总结
课程的位运算相关习题到这就算结束了,但是,我很清楚自己还差的很远,这只是位运算的冰封一角,还有太多的知识和技巧需要在未来的学习中掌握和积累。后续对位运算相关知识的计划就是从刷leetcode中继续学习,如果在这个过程中遇到一些妙(难)题,我肯定还是会第一时间总结和分享出来,感谢支持。
学海无涯,学路漫漫,唯有不畏前行,才能抵达自己的梦想之地!!!