面试题 05.01. 插入
插入。给定两个32位的整数N与M,以及表示比特位置的i与j。编写一种方法,将M插入N,使得M从N的第j位开始,到第i位结束。假定从j位到i位足以容纳M,也即若M = 10 011,那么j和i之间至少可容纳5个位。例如,不可能出现j = 3和i = 2的情况,因为第3位和第2位之间放不下M。
示例1:
输入:N = 10000000000, M = 10011, i = 2, j = 6
输出:N = 10001001100
示例2:
输入: N = 0, M = 11111, i = 0, j = 4
输出:N = 11111
答:这道题给了我一个知识,就是java中int的左移,不是直接左移,而是对32位取余之后左移。比如1<<32=1<<0=1;而不是我想的是0;
本题思路:
例如实例1:
10000000000先和
11110000011进行&运算,再和
1001100进行|运算。
即把填入部分先清空,在填充
//判断j>=31的,就是我想要的左移和java中不一致,我要的左移32之后,肯定为0。
public int insertBits(int N, int M, int i, int j) {
int k = j >= 31 ? ((1 << i) - 1) : (((~0) << (j + 1)) | ((1 << i) - 1));
return (N & k) | (M << i);
}
面试题 05.02. 二进制数转字符串
二进制数转字符串。给定一个介于0和1之间的实数(如0.72),类型为double,打印它的二进制表达式。如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”。
示例1:
输入:0.625
输出:“0.101”
示例2:
输入:0.1
输出:“ERROR”
提示:0.1无法被二进制准确表示
提示:
32位包括输出中的"0."这两位
public String printBin(double num) {
if (num == 0) {
return num + "";
}
if (num < 0 || num >= 1) {
return "ERROR";
}
//这么写不会通过,但是我认为是正确的。
//int length = 32;这么写会通过,但是是错误的,因为明显是利用了double的精确度不够
int length = (num + "").length();
StringBuffer sb = new StringBuffer(length);
sb.append("0.");
int k = 0;
while (num != 0 && (++k) <= length) {
num *= 2;
sb.append(num >= 1 ? "1" : "0");
num = num % 1;
}
if (num == 0) {
return sb.toString();
}
return "ERROR";
}
面试题 05.03. 翻转数位
给定一个32位整数 num,你可以将一个数位从0变为1。请编写一个程序,找出你能够获得的最长的一串1的长度。
示例 1:
输入: num = 1775(110111011112)
输出: 8
示例 2:
输入: num = 7(01112)
输出: 4
public int reverseBits(int num) {
//不带翻转的长度
int newLen = 0;
//带一次翻转的长度
int oldLen = 0;
int lastOne = -3;
int ans = 0;
for (int i = 0; i < 32; i++) {
if ((num & (1 << i)) == 0) {
oldLen = newLen;
oldLen++;
newLen = 0;
} else {
newLen++;
oldLen++;
if (newLen == 1 && i - lastOne != 2) {
oldLen = newLen;
}
lastOne = i;
}
ans = Math.max(ans, oldLen);
}
return ans;
}
面试题 05.04. 下一个数
下一个数。给定一个正整数,找出与其二进制表达式中1的个数相同且大小最接近的那两个数(一个略大,一个略小)。
示例1:
输入:num = 2(或者0b10)
输出:[4, 1] 或者([0b100, 0b1])
示例2:
输入:num = 1
输出:[2, -1]
提示:
num的范围在[1, 2147483647]之间;
如果找不到前一个或者后一个满足条件的正数,那么输出 -1。
public int[] findClosedNumbers(int num) {
int bigger = -1;
int letter = -1;
int n = num;
boolean getOne = false;
int oneNum = 0;
//找到最小的01,改成10然后把排在后面的1全部安排在最后,这样才会最小
for (int i = 0; i < 31; i++) {
if ((n & (1 << i)) > 0) {
n -= 1 << i;
oneNum++;
getOne = true;
} else {
if (getOne) {
n += 1 << i;
n += (1 << (oneNum - 1)) - 1;
bigger = n;
break;
}
}
}
n = num;
boolean getZero = false;
int zeroNum = 0;
//找到最小的10,改成01然后把排在后面的1全部安排在前,这样才会最大
for (int i = 0; i < 31; i++) {
if ((n & (1 << i)) == 0) {
zeroNum++;
getZero = true;
} else {
n -= 1 << i;
if (getZero) {
n += ((1 << (i + 1 - zeroNum)) - 1) << (zeroNum - 1);
letter = n;
break;
}
}
}
return new int[]{bigger, letter};
}
面试题 05.06. 整数转换
整数转换。编写一个函数,确定需要改变几个位才能将整数A转成整数B。
示例1:
输入:A = 29 (或者0b11101), B = 15(或者0b01111)
输出:2
示例2:
输入:A = 1,B = 2
输出:2
提示:
A,B范围在[-2147483648, 2147483647]之间
答:>>>和>>的区别是,前者无符号
-1>>1=-1
-1>>>1=2147483647
public int convertInteger(int A, int B) {
int c = A ^ B;
int ans = 0;
while (c != 0) {
ans += c & 1;
c = c >>> 1;
}
return ans;
}
面试题 05.07. 配对交换
配对交换。编写程序,交换某个整数的奇数位和偶数位,尽量使用较少的指令(也就是说,位0与位1交换,位2与位3交换,以此类推)。
示例1:
输入:num = 2(或者0b10)
输出 1 (或者 0b01)
示例2:
输入:num = 3
输出:3
提示:
num的范围在[0, 2^30 - 1]之间,不会发生整数溢出。
public int exchangeBits(int num) {
int ans = 0;
int k = 0;
while (num > 0) {
int v = num % 4;
num = num / 4;
if (v == 0 || v == 3) {
ans += v << (2 * (k++));
}
if (v == 1) {
ans += 2 << (2 * (k++));
}
if (v == 2) {
ans += 1 << (2 * (k++));
}
}
return ans;
}
面试题 05.08. 绘制直线
绘制直线。有个单色屏幕存储在一个一维数组中,使得32个连续像素可以存放在一个 int 里。屏幕宽度为w,且w可被32整除(即一个 int 不会分布在两行上),屏幕高度可由数组长度及屏幕宽度推算得出。请实现一个函数,绘制从点(x1, y)到点(x2, y)的水平线。
给出数组的长度 length,宽度 w(以比特为单位)、直线开始位置 x1(比特为单位)、直线结束位置 x2(比特为单位)、直线所在行数 y。返回绘制过后的数组。
示例1:
输入:length = 1, w = 32, x1 = 30, x2 = 31, y = 0
输出:[3]
说明:在第0行的第30位到第31为画一条直线,屏幕表示为[0b000000000000000000000000000000011]
示例2:
输入:length = 3, w = 96, x1 = 0, x2 = 95, y = 0
输出:[-1, -1, -1]
public int[] drawLine(int length, int w, int x1, int x2, int y) {
int wn = w / 32;
int[] ans = new int[length];
for (int i = y * wn; i <= length; i++) {
if (x1 >= 32) {
x1 -= 32;
x2 -= 32;
continue;
}
if (x2 <= 31) {
ans[i] = getAns(x1, x2);
break;
} else {
ans[i] = getAns(x1, 31);
x1 = 0;
x2 -= 32;
}
}
return ans;
}
private int getAns(int start, int end) {
int len = end - start + 1;
if (len == 32) {
return -1;
}
return ((1 << len) - 1) << (31 - end);
}