1. 求两个数的中间数
举例:在数组中我们要找到数组的中间下标位置
mid = l + (r - l) / 2mid = (l + r) / 2
int[] arr = new int[10];
int l = 0, r = arr.length - 1;
int mid = (l + r) / 2;
// 得到结果 mid = 5
1. 两种方法的对比
方法一是我们学习和理解问题初期想到的第一个方法,方法二是方法一化简后得来的,是我们在数学和我们平时的编程中是最常用也是刻在脑子里的方法。但方法二在编程中,有一个致命的缺陷: 因为编程中的int 类型是有边界的,当我们要计算的l和r很接近于边界值时,就可能使l + r大于int 的最大值,造成异常。
这里会有同学说:我们可以考虑将int改为long,这是一个不错的方法,大部分情况下是可以解决问题的。但我认为这是一种治标不治本的方法。这个时候我们是不是可以回过头看看方法一,是不是就可以解决这个问题了? 方法一再编程中我们还可以这样写:mid = l + (r - l) >> 1;
2. 两种方法的使用场景
- 方法一一般适用于所有的场景;
- 方法二适用于我们能确保两数相加不超出边界的情况。
2. 自己实现除法的上取整
计算机计算除法运算时,都是默认向下取整,如
11 / 2 = 5, 但有的时候,我们可能需要向上取整,如让11 / 2返回的结果为6。
1. 代码展示
/**
* 实现一个上取整的除法运算
* @param a 被除数
* @param b 除数
**/
public static int ceilDiv(int a, int b) {
// 方法一
// return a / b + (a % b > 0 ? 0 : 1)
// 方法二
return (a + b - 1) / b;
}
2. 两种方法的解释
方法一 这个方法比较好理解,如果 a/b 没有余数,那么就不存在上下取整的问题;如果 a/b 有余数,那么我们要向上取整,就把 商+1 就是上取整的结果了。
方法二 这个方法可能稍微绕了一点点。我们举两个例子可能更容易理解。如:
例1 8/5 => (8 + 5 - 1) / 5 = 12 / 5 = 2
例2 6/2 => (6 + 2 - 1) / 2 = 7 / 2 = 3
方法二的公式:a + (b - 1)。
我们来理解一下 b - 1, 实际上是 b 的最大余数。我们把被除数加了一个除数的最大余数,按照计算机的整数除法运算,① 如果没有余数,那我们加一个最大余数,也无济于事,最后还是会被丢掉;② 如果余数大于等于1,那么加一个最大余数,我们就会得到 商+1 的结果,就相当于向上取整了。
**这里可以看到两个方法的核心思想完全一致的:都是在有余数的情况下,进行了 商+1 的操作。**当然这也是向上取整的基本思想,不然也没有什么上下取整的概念了。哈哈~
3. 附:自己实现四舍五入
四舍五入,我们通常在结果后面 +0.5,后使用系统默认的 向下取整
(11 / 2f) + 0.5f = 5.5 + 0.5 = 6;
(10 / 4f) + 0.5f = 2.25 + 0.5 = 2.75 = 2