背景:
在寫力扣題目“搜素插入位置 ”時,發現二分法的一個細節點,打算記錄下來,先看一張圖:
我們知道,排序數組,更高效的是二分查找法~~~而二分法就是切割中間,定義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;}
}