題目描述
給定一個 n 個元素有序的(升序)整型數組 nums 和一個目標值 target ,寫一個函數搜索 nums 中的 target,如果目標值存在返回下標,否則返回 -1。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/binary-search
著作權歸領釦網絡所有。
栗子1
輸入: nums = [-1,0,3,5,9,12], target = 9
輸出: 4
解釋: 9 出現在 nums 中並且下標爲 4
栗子2
輸入: nums = [-1,0,3,5,9,12], target = 2
輸出: -1
解釋: 2 不存在 nums 中因此返回 -1
提示
你可以假設 nums 中的所有元素是不重複的。
n 將在 [1, 10000]之間。
nums 的每個元素都將在 [-9999, 9999]之間。
思路
題目直接以二分查找命名,解題方案不言而喻。提示中說到所有元素不重複,所以最基本的二分查找就可以了。可以選擇遞歸的方式或非遞歸的方式。這裏我選擇了遞歸,如果你想換一種方式,可以思考如何去實現。
又到了老生常談的問題了,二分查找需要注意的幾個地方。
- 查找的條件;
- mid的寫法;
- mid+1和mid-1。
1、我們查找的區間是整個數組,下標0開始,下標nums.length - 1結束。這是我選擇的邊界,只要在這個閉區間[0,nums.length - 1],即low<=high,就去執行程序。你可能會問爲什麼會有等於的情況?
把數字帶進去就懂了[6,6],這時候區間還有一個6需要比較;如果沒有等號就是[6,6),會直接把6漏掉。
2、mid=(low+high)/2;這種方式應該都會理解的,但是如果low和high比較大的話,兩者之和就有可能會溢出。所以就有了改進,將mid的計算寫成low+(high-low)/2。你以爲這就結束了嗎?並沒有,還可以寫成mid=low+((high-low)>>1)。因爲位運算要比除法更快,不過這樣寫一定要注意優先級。
3、low=mid+1,high=mid-1;這裏有+1和-1,因爲我們最先比較的就是索引爲mid的元素,下次比較就不用再比較它了。而且如果直接寫成 low=mid 或者 high=mid,可能會發生死循環。
比如,當 high=2,low=2 時,如果 a[2]不等於 target,就會導致一直循環不退出。
考慮了這些問題再寫代碼就會大大提高勝率了。你的代碼可能和我的不一樣,沒關係,條條大路通羅馬,而且每個人的想法都是不一樣的。只要是對的就可以。
如果有什麼錯誤或者問題,歡迎評論,我們一起探討,一起進步。
代碼
private int searchRecursive(int[] a, int low, int high, int target) {
if (low > high) {
return -1;
}
int mid = low + ((high - low) >> 1);
if (a[mid] == target) {
return mid;
} else if (a[mid] > target) {
return searchRecursive(a, low, mid - 1, target);
} else {
return searchRecursive(a, mid + 1, high, target);
}
}
public int search(int[] nums, int target) {
return searchRecursive(nums, 0, nums.length - 1, target);
}