题目一
给定两个有符号32位整数a和b,返回a和b中较大的。【要求,不用做任何比较判断】
相关代码:
public class Code03_MaxHappy {
//想法:c = a - b 如果得数是正返回a,得数是负返回b
//因为不能用比较,所以可以依据c的最高位是1还是0进行判断
public static int getMax1(int a, int b){
int c = sign(a - b);
return c == 0 ? a : b;
}
public static int sign(int n){
return (n >> 31) & 1;
}
public static void main(String[] args) {
System.out.println(getMax1(-2,2));
}
}
但是上面a - b 可能会溢出,产生错误的答案,如 a = -2147483648, b = 2147483647
修正代码:
public class Code03_MaxHappy {
//想法:c = a - b 如果得数是正返回a,得数是负返回b
//因为不能用比较,所以可以依据c的最高位是1还是0进行判断
public static int getMax1(int a, int b){
int c = sign(a - b);
int sa = sign(a);//a的符号
int sb = sign(b);//b的符号
//返回a的情况:同符号的情况下,差值c的最高位是0;或者不同符号的情况下,a的最高位是0
return (c == 0 && sa == sb) || (sa != sb && sa == 0) ? a : b;
}
public static int sign(int n){
return (n >> 31) & 1;
}
public static void main(String[] args) {
System.out.println(getMax1(-2147483648,2147483647));
}
}
题目二
判断一个32位正数是不是2的幂、4的幂
是不是2的幂相关代码:
class Solution {
public boolean isPowerOfTwo(int n) {
if(n <= 0){
return false;
}
int r = n & (~ n + 1);//右边最近的1
return r != n ? false : true;
}
}
=========================================
class Solution {
public boolean isPowerOfTwo(int n) {
if(n <= 0){
return false;
}
int r = n & (n - 1);//n - 1会将最右边的1给打散掉,与上原来的就是0
return r != 0 ? false : true;
}
}
是不是4的幂相关代码:
class Solution {
public boolean isPowerOfFour(int n) {
if(n < 0){
return false;
}
int res = n & (n - 1);//是4的幂就一定是2的幂。所以只有一个1
//满足是2的幂后应该这个数 & 01010101 01010101 01010101 01010101 应该 != 0
// return res == 0 && (n & 0b01010101010101010101010101010101) != 0 ? true : false;
return res == 0 && (n & 0x55555555) != 0 ? true : false;
}
}
题目三
给定两个有符号32位整数a和b,不能使用算术运算符,分别实现a和b的加、减、乘、除运算
要求:如果给定a、b执行加减乘除的运算结果就会导致数据的溢出,那么你实现的函数不必对此负责,除此之外请保证计算过程不发生溢出
加法
相关分析:不断地算无进位相加和进位信息的结果,直到有一步没有了进位信息
class Solution {
public int add(int a, int b) {
int sum = a;
while(b != 0){
sum = a ^ b;
b = (a & b) << 1;
a = sum;
}
return sum;
}
}
减法
class Solution {
public int add(int a, int b) {
//减法相当于相反数
b = ~b + 1;
int sum = a;
while(b != 0){
sum = a ^ b;
b = (a & b) << 1;
a = sum;
}
return sum;
}
}
乘法
处理的方法和加法类似,乘法相当于多个加法
在B中遇到0,直接跳过,遇到1,就是重复A,但是要注意左移几位
class Solution {
public int multiply(int A, int B) {
int res = 0;
while(B != 0){
//遇到B中的1,停下来相加,没有直接跳过
if((B & 1) != 0){
res = add(res,A);
}
//A不断的左移一位
A <<= 1;
//方便辨认出B中相应位是0还是1
B >>>= 1;
}
return res;
}
public int add(int A, int B){
int sum = 0;
while(B != 0){
sum = A ^ B;
B = (A & B) << 1;
A = sum;
}
return sum;
}
}
除法
class Solution {
public int divide(int dividend, int divisor) {
//因为除法的特殊性,所以对最大最小值进行单独的考虑,因为最小值是
//-2147483648,而最大值是2147483647,这时候进行绝对值并且移动31位就会出错
int ret = 0;
//除数与被除数都是系统最小,结果返回1
if(divisor == Integer.MIN_VALUE && dividend == Integer.MIN_VALUE){
return 1;
//除数是系统最小,结果返回0
}else if(divisor == Integer.MIN_VALUE){
return 0;
//除数是-1,被除数是系统最小,结果返回2147483647,因为系统最大就是这个,没有2147483648
}else if(divisor == -1 && dividend == Integer.MIN_VALUE){
return Integer.MAX_VALUE;
//上面条件过完时候,被除数是系统最小
}else if(dividend == Integer.MIN_VALUE){
//先让被除数加1,变成-2147483647进行计算,得到ret
ret = divide((dividend + 1), divisor);
//计算ret与除数相乘后与原数相差多少,相差的部分再除以除数,得到的结果加上ret
//注意是原数 - (ret与除数相乘)
return ret + divide((dividend - multi(ret, divisor)), divisor);
}
int isFu = 1;
//相同是0,也就是返回正的
if(((dividend >> 31) ^ (divisor >> 31)) == 0){
isFu = 0;
}
//因为-7/2 和 7/-2是相同的答案,所以都转化成正数做,正负号做一些标记即可
dividend = Math.abs(dividend);
divisor = Math.abs(divisor);
//除法的核心代码
//这里的向右移动和图中的意思是等价的,以为担心符号位的问题,
//所以向左移动会有风险,所以直接向右移动
for(int i = 31; i > -1; i--){
//找到不大于被除数的最大移动
if((dividend >> i) >= divisor){
//结果或上
ret |= (1 << i);
//被除数减去对应的,依次再进行
dividend = dividend - (divisor << i);
}
}
//依据标记的正负号进行最后的修饰
return isFu == 0 ? ret : -1 * ret;
}
//位运算乘法
public int multi(int a, int b){
int res = 0;
while(b != 0){
if((b & 1) != 0){
res += a;
}
a <<= 1;
b >>>= 1;
}
return res;
}
}