34 Search for a Range
Given an array of integers sorted in ascending order, find the starting and ending position of a given target value.Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].
對應一個已經排好序的數組+尋找target+O(log n),最先想到的算法應該就是二分查找算法了。但是我們學過的最基礎的二分查找算法主要是針對查找一個目標值而非一個範圍,這個時候,便需要在範圍比較判定賦值上面下功夫了。
一個普通的二分查找:
while(low <= high){
int mid = (low + high)/2;
if(nums[mid] == target) {
return mid;
}
else if(nums[mid] > target) {
high = mid - 1;
}
else {
low = mid + 1;
}
}
每次取中間值,如果恰好等於目標,即找到了目標值,直接返回,若是中間值比目標值大,則說明目標在數列的左半邊,在數列的左半邊進行下一次尋找,若是中間值比目標值小,則在數列的右半邊進行尋找,如此重複知道找到目標值(或者不存在)爲止。
而這題要求邊界,即是在可能有複數個目標值的情況下,找到最左邊的那個目標值(下界)和最右邊的那個目標值(上界),所以需要在普通的二分查找中進行判斷條件和邊界賦值的修改。
下界二分查找:
while(low < high) {
int mid = (low + high) / 2;
if(nums[mid] < target)
low = mid + 1;
else
high = mid;
}
if(nums[low] != target)
return -1;
else return low;
關鍵是每次判斷nums[mid]與target的大小重新選定查找範圍時,若取左半邊時,將nums[mid]也包括進去,使得當target有複數個值的時候,最左邊的那個(第一個)會一直在搜索範圍之內,直到最後退出while循環的時候,只剩下一個元素(即第一個目標值)或者是找不到目標,完成了搜索。
上界二分查找:
while(low < high) {
int mid = (low + high + 1) / 2;
if(nums[mid] > target)
high = mid - 1;
else
low = mid;
}
if(nums[high] != target)
return -1;
else return high;
思想與下界二分查找類似,但是此時mid = (low + high + 1) / 2,保證當搜索數列只剩兩位的時候不會陷入死循環(取右)。
對於這道題便可以使用兩次二分查找分別查找到值等於target的第一次出現的位置(最左邊的target)和最後一次出現的位置(最右邊的target),從而達成在O(log n)的時間複雜度下求出其範圍。
當然還要注意越界問題,當nums爲空的時候會出現越界,所以要拿出來單獨考慮。
參考代碼如下:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int i = 0;
int j = nums.size() -1;
int mid;
vector<int> result;
// set default
result.push_back(-1);
result.push_back(-1);
// find the lower bound
if(j == -1)
return result;
while(i < j) {
mid = (i + j) / 2;
if (nums[mid] < target)
i = mid + 1;
else
j = mid;
}
if(nums[i] != target)
return result;
else
result[0] = i;
// find the upper bound
j = nums.size() -1;
while(i < j) {
mid = (i + j + 1) / 2;
if(nums[mid] > target)
j = mid - 1;
else
i = mid;
}
result[1] = j;
return result;
}
};