算法小技巧

求2个数的中间值

先说结论:int mid = (start + end) >>> 1

二分查找中我们需要根据 start 和 end 求中点,正常情况下加起来除以 2 即可。

int mid = (start + end) / 2

但这样有一个缺点,我们知道int的最大值是 Integer.MAX_VALUE ,也就是2147483647。那么有一个问题,如果 start = 2147483645,end = = 2147483645,虽然 start 和 end都没有超出最大值,但是如果利用上边的公式,加起来的话就会造成溢出,从而导致mid计算错误。

解决的一个方案就是利用数学上的技巧,我们可以加一个 start 再减一个 start 将公式变形。

(start + end) / 2 = (start + end + start - start) / 2 = start + (end - start) / 2

这样的话,就解决了上边的问题。

然后当时和同学看到jdk源码中,求mid的方法如下

int mid = (start + end) >>> 1

它通过移位实现了除以 2,但。。。这样难道不会导致溢出吗?

首先大家可以补一下 补码 的知识。

其实问题的关键就是这里了>>> ,我们知道还有一种右移是>>。区别在于>>为有符号右移,右移以后最高位保持原来的最高位。而>>>这个右移的话最高位补 0。

所以这里其实利用到了整数的补码形式,最高位其实是符号位,所以当 start + end溢出的时候,其实本质上只是符号位收到了进位,而>>>这个右移可以带着符号位右移,所以之前的信息没有丢掉。

但>>有符号右移就会出现问题了,事实上 JDK6 之前都用的>>,这个 BUG 在 java 里竟然隐藏了十年之久。

大小写转换

结论:chars[i] ^= (1 << 5);

使用异或运算转换字母大小写。

我们发现大写字符与其对应的小写字符的 ASCII 的差为 32,32 这个值如果敏感的话,它是 2^5
,在编程语言中,可以表示为 1 << 5。而

变换大小写这件事等价于:

1、如果字符是小写字符,减去 32 得到大写字符;
2、如果字符是大写字符,加上 32 得到小写字符。

而这两者合并起来,就是给这个字符做一次不进位的加法,即异或上 1 << 5。

原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/11426281.html