二分法算法技巧-思维提升
背景:
在写力扣题目“搜素插入位置 ”时,发现二分法的一个细节点,打算记录下来,先看一张图:
我们知道,排序数组,更高效的是二分查找法~~~而二分法就是切割中间,定义left是最开始的,也就是下标为0;right 是最后一个
那么这个mid到底怎么写?
简单想到的是:int mid = (left + right) / 2;
但是还有更好的写法!那就是:int mid = left + (right - left) / 2
原因解析
1. 防止整数溢出(关键原因)
假设:
left = 2000000000right = 2100000000 (21亿)
使用 (left + right) / 2
:的情况下:
left + right = 2000000000 + 2100000000 = 4100000000
但 int
最大只能存储 2147483647(约21亿),会导致整数溢出变成负数!
使用 left + (right - left) / 2
:的情况下:
right - left = 100000000
(right - left)/2 = 50000000
left + 50000000 = 2050000000
完全不会溢出!!!!
2. 数学等价性
两者数学上是等价的:
left + (right - left)/2
= left + right/2 - left/2
= left/2 + right/2
= (left + right)/2
但计算机的整数运算会截断小数,所以写法不同会影响结果。
对比总结
写法 | 安全性 | 可读性 | 推荐度 |
---|---|---|---|
(left + right)/2 | 可能溢出 | 更直观 | ❌ 不推荐 |
left + (right - left)/2 | 绝对安全 | 稍复杂 | ✅ 推荐 |
案例题目练习:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2
代码实现:
class Solution {public int searchInsert(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] == target) {return mid;} else if (nums[mid] < target) {left = mid + 1;} else {right = mid - 1;}}return left;}
}