不能使用大于小于号,如何判断两个正整数的大小?
- 标签:后端、场景题
🏛 业务架构师
不能用大于小于号比较两个正整数,考察的是位运算和算术等价变换,我给三种思路,并主动讲清各自的坑——这题答完就收,别恋战。
思路一:相减判符号位(最简洁)
java
int diff = a - b;
boolean aGreater = (diff >>> 31) == 0; // 无符号右移看符号位a - b 为正说明 a 大,>>> 31 取出符号位(0 正 1 负)。坑:溢出——a 是 Integer.MAX_VALUE、b 是 -1 之外的负数场景会翻转(此题限定正整数,但 a=20 亿、b=-20 亿才溢出,两正数相减不溢出的界是差值在 int 范围内;严格稳妥用 long):
java
boolean aGreater = ((long) a - b) >>> 63 == 0;思路二:从最高位逐位比较(无溢出,绝对安全)
java
for (int i = 31; i >= 0; i--) {
int bitA = (a >> i) & 1, bitB = (b >> i) & 1;
if (bitA != bitB) return bitA == 1 ? a : b;
}
return 0; // 相等从高位往下找第一个不同的位,该位为 1 的大——模拟硬件比较器的原理。
思路三:借用 API(说明思维灵活)
java
int r = Integer.compare(a, b); // 底层还是比较运算
Math.max(a, b);收尾:这题在面试里的价值是考察边界意识(溢出)和底层理解(符号位、逐位比较),答出思路一 + 溢出讨论即可满分。业务工程里当然直接 Math.max——知道什么时候用技巧、什么时候用常识,都是工程师的能力。
🏗 系统架构师
不用大于小于号比较正整数,我给三个思路:作差看符号位、树状判断、位运算。
1. 作差法(最快想到)a - b 的结果的最高位(符号位)是 1 则 a < b。Java 实现:
java
int diff = a - b;
if (diff == 0) return 0; // 相等
// diff 符号位:负数为 1
boolean aSmaller = ((diff >>> 31) & 1) == 1;
// 还要防溢出:a=2^31-1, b=-... 正整数场景 a-b 可能溢出溢出是这个解法的坑:两个正 int 相减可能超出 int 范围导致符号位翻转,误判。稳妥做法是用 long diff = (long) a - b;,long 范围内两个 int 正数之差不会溢出,然后看 diff >>> 63。
2. 二分比较(位运算,无溢出) 从最高位开始逐位比较,先比出高位大小即分胜负:
java
for (int i = 31; i >= 0; i--) {
int ba = (a >>> i) & 1, bb = (b >>> i) & 1;
if (ba != bb) return ba == 1 ? 1 : -1; // 高位为1者大
}
return 0;不需要减法,无溢出风险,O(32) 常数复杂度。
3. 分情况讨论法max(a, b) = (a + b + |a - b|) / 2,其中 |a-b| 用 (diff ^ (diff >> 31)) - (diff >> 31) 求绝对值——同样要处理溢出。
面试答题策略:先用作差法展示直觉,主动指出溢出问题并用 long 修复,再给逐位二分法展示位运算功底——两步走完,比背一个答案更能体现严谨性。
💻 全栈开发专家
不用大于小于号,我有三种思路,面试推荐位运算版。
思路一:看符号位(位运算,最快)
两个 int 相减,结果的最高位(符号位)暴露大小关系:
java
public static int compare(int a, int b) {
return ((a - b) >> 31) & 1; // 1: a<b, 0: a>=b
}原理:负数符号位是 1,算术右移 31 位把符号位铺满 32 位,& 1 取出。但注意溢出坑:a - b 在 a 大 b 负得深时(如 Integer.MAX_VALUE - (-1))会溢出导致符号位反转。修正:用 long 承接差值:
java
long diff = (long) a - (long) b;
int sign = (int) ((diff >> 63) & 1); // 1: a<b思路二:比较最高不同的位
java
int x = a ^ b; // 1 的位置就是不同位
x |= x >> 1; // 把最高位扩散到低位
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16; // 现在 x 的最高位以下全是1(位掩码)
int k = x ^ (x >> 1); // 只剩最高不同位
// a 在该位是 1 则 a 大:
boolean aBigger = (a & k) != 0;无溢出问题,纯位运算,适合讲原理。
思路三:Math/循环
Integer.signum(a - b)(内部还是位运算,有溢出问题)。- 更小的数连减另一个数先到 0,但这本质是比较,效率低。
面试要点:写出思路一 + 主动提溢出及 long 修正,基本满分。