本文旨在对于个人知识的梳理以及知识的分享,如果有不足的地方,欢迎大家在评论区指出
题目描述
编写一个方法,找出两个数字a和b中最大的那一个。不得使用if-else或其他比较运算符。
示例:
输入: a = 1, b = 2
输出: 2
题目链接
题目分析
题目中要求我们不可以使用任何的比较运算,所以自然而然想到可以使用位运算来解决,首先说我个人的思路,题目中数字的范围都在int范围内,首先如果两个数字符号不同,则直接返回正数,如果相同的话,那么int的最高位为31,从最高位开始枚举,谁的最高位先有1,则代表谁越大,这里可能会有一个疑惑就是正数这样比较是ok的,那么负数为什么也行呢,这里就先介绍一个下面也会用到的概念,计算机中的负数是以补码的形式存储的,补码是原码取反之后加1的值,例如9的原码是00001001
,而-9的补码为11110111,也就是说如果其中一个负数的高位为1而另一个为0,则它对应的正数的值要小,那么加上负号值就大了,这也就是为什么负数也ok的原因
另外还有一种思路,更偏向于数学方面,对于
M
a
x
(
a
,
b
)
Max(a, b)
Max(a,b),它的值其实等于
a
+
b
+
a
b
s
(
a
−
b
)
2
\frac{a + b + abs(a-b)}{2}
2a+b+abs(a−b),在代码中,abs
函数是含有比较运算的,所以我们可以重写abs,为了防止int溢出,我们统一使用long类型,对于重写的abs
函数,思路如下,首先我们要判断当前数字的正负号,在计算机中,最高位存储的是数字的符号,所以x >> 63
就可以获得x的符号flag
,如果为正数,那么flag=0
,如果为负数,那么flag=-1
,之后我们取x的绝对值为(x^flag)-flag
,这里比较巧妙,我们可以举个例子看一下对不对,首先当x为正数的时候,发现返回的就是x本身,当x为负数的时候,由于和-1
异或就相当于每一位都取反,之后再+1,这个操作其实就是补码转原码的操作,也就是对符号取反了
解题代码
解法①:
Java
class Solution {
public int maximum(int a, int b) {
if(a>0&&b<0) return a;
if(a<0&&b>0) return b;
int k = 31;
while(k -- >= 0){
if((a>>k&1)==1&&(b>>k&1)==0) return a;
if((b>>k&1)==1&&(a>>k&1)==0) return b;
}
return a;
}
}
Python
class Solution:
def maximum(self, a: int, b: int) -> int:
if a>0 and b<0:
return a
if a<0 and b>0:
return b
k = 31
while k >= 0:
if ((a>>k&1) == 1 and (b>>k&1) == 0):
return a
if ((b>>k&1) == 1 and (a>>k&1) == 0):
return b
k -= 1
return a
解法②:
Java
class Solution {
private long myAbs(long a){
int flag = (int)(a>>63);
return (flag^a)-flag;
}
public int maximum(int a, int b) {
long la = a; long lb = b;
return (int)((la+lb+myAbs(la-lb))/2);
}
}
Python
class Solution:
def maximum(self, a: int, b: int) -> int:
# 自定义绝对值函数
def myAbs(a):
flag = a>>63
return (flag^a)-flag
return (a+b+myAbs(a-b))//2