力扣704. 二分查找
#include <vector>
using namespace std;class Solution {
public:int search(vector<int>& nums, int target) {int left = 0;int right = (int)nums.size() - 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 -1; // 找不到目标返回-1}
};#include <iostream>int main() {Solution sol;int arr[] = {-1,0,3,5,9,12};int n = sizeof(arr)/sizeof(arr[0]);vector<int> nums(arr, arr + n);cout << sol.search(nums, 9) << endl; // 输出 4return 0;
}
本题小结:
int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
int middle = left + ((right - left) >> 1);
假设直接用 (left + right) / 2
,如果 left
和 right
都是很大的整数,它们相加可能会超过 int
类型的最大表示范围(如32位整型范围约为 -2,147,483,648 到 2,147,483,647),从而产生整数溢出,导致结果变成负数或错误值。
而用 left + ((right - left) / 2)
,括号内先算 right - left
,这一步不会超过整数范围(因为 right >= left
),再除以2,最后加上 left
,这三个数值都不会溢出。实际上这两种计算方式数学上是等价的,但后者避免了 left + right
可能带来的溢出风险。
因此,这种写法是二分查找中计算中点时常用的防溢出安全写法。