1、前言
在经历一个月的面试后,笔者回到家休息,不曾想晚上10点多收到Base地广州某大厂第二天早上的面试,为了把握秋招的每次机会,笔者连夜回学校取回电脑,全力面对第二天的面试,不曾想面的稀碎!
(本文有水印的图片是笔者在自己其他博客网站拷过来附带的)
2、反转long
面试的三道coding中有一道反转long的题目,下面介绍下原题大概的内容:
给出一个无符号long类型数字,反转其64位比特位,并计算运行1000万次所需要的耗时。
public static void main(String[] args) {
long num = 4;
String numStr = Long.toBinaryString(num);
String swapNumStr = Long.toBinaryString(swapLong(num));
System.out.println(check(numStr, swapNumStr));
long t1 = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
swapLong(num);
}
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);
}
public static boolean check(String source,String target){
StringBuilder sb1 = new StringBuilder(source);
StringBuilder sb2 = new StringBuilder(target);
//补0
while (sb1.length() < 64){
sb1.insert(0,"0");
}
while (sb2.length() < 64){
sb2.insert(0,"0");
}
System.out.println(sb1);
System.out.println(sb2);
return sb1.reverse().toString().equals(sb2.toString());
}
public static long swapLong(long val){
long result = 0;
int num = 1;
//左移
while (num <= 32){
//为1的位置
int index = 32 + num;
long fix = 1;
for (int i = 1; i < index; i++) {
fix = fix << 1;
}
result += ((val << (1 + 2*(num-1))) & fix);
num++;
}
//右移
num = 1;
while (num <= 32){
//为1的位置
int index = 33 - num;
long fix = 1;
for (int i = 1; i < index; i++) {
fix = fix << 1;
}
result += ((val >>> (1 + 2*(num-1))) & fix);
num++;
}
return result;
}
输出为
大概思路是将64位比特分为左右两半,找到右边比特位反转后的位置(算第一位为1,那么第30位反转后应该到第35位),计算出位置后,通过位操作得到一个fix(这个数从二进制角度来看只有一个位是1,其余是0,而1那个位正是反转后的位置)。然后只需要对val做位操作,使需要反转的比特位移到对应的位置,再通过位与运算,就可以得到该位上的值,然后相加,这样的操作重复64次(左边32次,右边32次),最后即可得到结果。
3、注意点
补零
计算完之后通过Long.toBinaryString换算成二进制字符串后,要记得补0,笔者就是面试的时候写出来了,换算成二进制字符串后发现不对劲,以为自己写错了
上面这副图就是不补零直接输出的效果,一眼看过去就以为自己写错了。可能有人问,为什么不是补1呢?有可能他反转后是个负数呢?
下面看一个数为327179121787189L的例子
可以看到,如果反转后最高位是1,那么其实他是不会被忽略掉的,前面的例子是因为最高几位是0,所以把最高几位都忽略掉了,才导致看起来出错的情况
计算fix
这里计算fix有人可能觉得使用Math.pow也可以,笔者面试时也是用这个函数,但是确出现了一些诡异的情况,在计算到第64位时,这个值会减1
long pow = (long) Math.pow(2, 63);//计算第64位为1的fix
System.out.println(pow);
System.out.println(Long.toBinaryString(pow));
正常来说应该是9223372036854775808,但是值却减了1,个人认为是因为long最大值就是9223372036854775807,所以java自动帮你调为了这个值(求2的67次方也是会得到这个值),因为该方法时native方法看不到其实现
4、总结
总的来说,在做这些现场coding最好所有方法都由自己实现,否则出现一些奇怪的bug,可能会扰乱自己的心态,在这里也祝大家(还有笔者)秋招都有offer