题目一
给定2个有符号32位整数a和b,返回较大的
要求不要做任何比较判断
借助两个辅助函数,用互斥情况相加得到较大的数:
// 输入为0或1
// 1->0
// 0->1
public static int flip(int n) {
return n ^ 1;
}
// 返回n的符号
// n为非负数,返回1
// n为负数,返回0
public static int sign(int n) {
return flip((n >> 31) & 1); // n右移31位,得到符号位,与1后,得到返回值的相反数,再flip一下
}
public static int getMax1(int a, int b) {
int c = a - b;
int scA = sign(c); // a-b非负,该值为1;a-b负,该值为0
int scB = flip(scA); // 与scA相反
return a * scA + b * scB;
}
上面代码可能出现a-b的溢出,改进:
public static int getMax2(int a, int b) {
int c = a - b; // 可能溢出
int sa = sign(a);
int sb = sign(b);
int sc = sign(c);
int diffSab = sa ^ sb; // a和b符号不同,为1;符号相同,为0
int sameSab = flip(diffSab);
// a和b符号相同(不会溢出),sc为1,返回a
// a和b符号不同,且a>0,返回a
int returnA = diffSab * sa + sameSab * sc; // 两部分互斥,代表两种返回a(a大于b)的情况
int returnB = flip(returnA);
return a * returnA + b * returnB;
}
题目二
判断一个32位正数是否为2的幂、4的幂
是2的幂,则二进制表示中只有一个位是1,判断方式:拿到最右侧的1,计算只有这个位置是1的数,是否与原来的数相等,若相等原来的数就是2的幂
或者计算KaTeX parse error: Expected 'EOF', got '&' at position 2: x&̲(x-1),若结果为0,则x为2的幂
是4的幂,前提是2的幂,即二进制表示中只有一个位是1,并且这个1在第1、3、5······这些位上
所以先判断x是2的幂,然后计算010101···0101&x,若结果为0,不是4的幂,结果不为0,则是4的幂
public static boolean is2Power(int n) {
return (n & (n - 1)) == 0;
}
public static boolean is4Power(int n) {
return (n & (n - 1)) == 0 && (n & 0x55555555) != 0;
}
题目三
给定2个有符号32位整数a和b,不适用算术运算符,完成加减乘除运算
【要求】不考虑给定的ab导致溢出的情况
1、加法
例如:
13:01101
7: 00111
异或^->无进位相加
01010
&并且左移1位->13+7的进位信息
01010
将上述两个结果相加,即为13+7的和
继续用上述步骤计算01010和01010的和
异或得:00000
&并且左移1位:10100
计算00000和10100的和
异或得:10100
&并且左移1位:00000
发现没有进位了,结果就是10100=20
public static int add(int a, int b) { // 默认不溢出
int yihuo = 0;
while (b != 0) {
yihuo = a ^ b;
b = (a & b) << 1;
a = yihuo;
} // 直到进位信息为0
return yihuo;
}
2、减法
a-b=a+(b的相反数)
b的相反数=b取反+1
public static int minus(int a, int b) {
return add(a, negNum(b));
}
public static int negNum(int b) { // 求b的相反数:取反加1
return add(~b, 1);
}
3、乘法
回忆一下小学学的乘法
public static int multi(int a, int b) {
int res = 0;
while (b != 0) {
if ((b & 1) != 0) { // 看b的最后一位是1或0
res = add(res, a);
}
a <<= 1; // a左移1位
b >>>= 1; // 无符号右移,即右移过程中,左边一直补0
}
return res;
}
4、除法
a/b
假设
a=0110110
b=0000101
b左移若干位,尽量移动很多位,但不要大于a
在这里b<<3,相当于乘以8,则a中一定包含1000(2)个b
左移得到b’=0101000
计算a’=a-b’
再使b左移若干位,去逼近a’
在这里b<<2,所以一定包含0100(2)个b
此时a’‘=a’-b’'=0
结束,除法结果为01100
public static int div(int a, int b) {
int x = isNeg(a) ? negNum(a) : a;
int y = isNeg(b) ? negNum(b) : b;
int res = 0;
for (int i = 31; i > -1; i = minus(i, 1)) {
if (((x >> i) >= y)) { // 不直接让y左移,因为有可能移成负数
res |= (1 << i);
x = minus(x, y << i);
}
}
return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
}
public static boolean isNeg(int n) {
return n < 0;
}