Search for a Range問題
Search for a Range問題
leetcodejava二分查找1. 問題描述
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].
題目翻譯:
給定一個按照遞增排序的整數數組,查找一個數值開始和結束的位置。算法的復雜度要求必須是O(logn)。如果找到目標就返回一個int類型的數組[start,end],如果目標沒有找到,返回[-1,-1]。
2.解題思路
在一個已經排序的數組中查找一個數值,並且算法的復雜度要求是O(logn),這種類型的題目使用二分法來做的,所以看到這道題基本的思路就能確定下來。難點就是怎麽確定這個數值的左右邊界,並且能夠滿足復雜度的要求。
首先要利用二分法確定這個數組中是否包含這個數值,同時能夠獲得這個數值一個索引,這個索引一定包含start和end的範圍內。那麽就以這個索引為基礎想兩邊擴張。擴張的時候依然使用二分查找來做。當在左邊的區域中找到一個對應的數值,那就以這個位置為有邊界繼續向左擴張範圍。同樣,當在右邊找到一個對應的數值,就以這個數值為左邊界繼續向右尋找。直到找不到對應的數值,那麽這個數值的範圍就能確定。
3.代碼實現
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] res ={-1,-1};
int len = nums.length;
if(nums==null||len==0)//判斷數組是否為空
return res;
int begin =0;
int end = len-1;
int pos = binarySearch(nums,0,end,target);//判斷數組中是否包含target
if(pos==-1)
return res;
begin=end= pos;
while( begin != -1){//以pos為右邊界向左擴張
res[0] = begin;
if(begin>0)//這裏要註意邊界情況,否則發生越界
begin = binarySearch(nums,0,begin-1,target);
else
begin=-1;
}
int l1 = len -1;
while(end != -1){//以pos為左邊界向右擴張
res[1] = end;
if(end<l1)//註意邊界情況
end = binarySearch(nums,end+1,l1,target);
else
end =-1;
}
return res;
}
//二分查找的實現
public int binarySearch(int[] nums,int begin, int end,int target){
int mid =0;
while(begin<end){
mid = begin+(end-begin)/2;//為了防止溢出的小trick
if(target==nums[mid])
return mid;
if(target>nums[mid])
begin = mid+1;
else
end = mid-1;
}
return target==nums[begin]?begin:-1;//判斷是否相等,並返回索引
}
}
上面是按照自己的思路來實現的代碼嚴格來說當數組中的元素完全重復的時候,復雜度會變成O(n),下面的代碼是參考了Discuss裏面排行第一的講解寫出的代碼,人家的想法確實很優秀,為了方便查看,點擊這裏:
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] res ={-1,-1};
int len = nums.length;
if(nums==null||len==0)
return res;
int begin =0;
int end = len-1;
int mid =0;
while(begin<end){//這個循環不僅確定了start的位置也確定了數組中是否存在target
mid = begin+(end-begin)/2;
if(nums[mid]<target)
begin = mid+1;
else//else if(target<=nums[mid])
//處理的技巧在這裏,這樣做不僅收縮了範圍,end也保存了target的位置信息
end = mid;
}
if(target==nums[begin])
res[0] = begin;
else
return res;
end = len-1;
while(begin<end){//以begin為左邊界向右尋找右邊界
mid = (begin+end)/2+1;//這裏也有一個小trick
if(nums[mid]>target)
end = mid-1;
else
begin = mid;
}
res[1] = end;
return res;
}
}
Search for a Range問題