T34. Search for a Range【Medium】
題目
給定以升序排序的整數數組,找到給定目標值(target)的開始和結束位置。
如果沒有找到目標值,就返回[-1,-1]
注意: 算法時間復雜度必須是 O(logn)
例如,
給出數組 [5,7,7,8,8,10]
則返回 [3,4]
思路
因為是排好序的數組,所以肯定想到要用二分法。
但是這里有一個問題,如果有多個重復的目標值,怎么確定二分法找到數的恰巧是首位或者末尾的數呢,這是要說的重點。我在代碼里標記了 標記1 和 標記2,問題就是在那里解決的。
找到 標記1,當 nums[mid] >= target 時,它會繼續取前半段
找到 標記2,當 nums[mid] >= target 時,它會繼續取后半段
這樣取下去,findFirst() 方法返回的就一定是目標值得首位,而 findLast() 方法返回的就一定是目標值得末位。
當然,若找不到的話就返回 -1。
知道這個關鍵點其他看代碼就好啦!
代碼
代碼取自 Top Solution,稍作注釋
public class Solution {
public int[] searchRange(int[] nums, int target) {
//初始化一個有兩個元素的數組用來返回
int[] result = new int[2];
//找到數字的起始序號
result[0] = findFirst(nums, target);
//找到數字的終止序號
result[1] = findLast(nums, target);
return result;
}
//二分法不用多說
private int findFirst(int[] nums, int target){
int idx = -1;
int start = 0;
int end = nums.length - 1;
while(start <= end){
int mid = (start + end) / 2;
//標記1,在思路里說
if(nums[mid] >= target){
end = mid - 1;
}else{
start = mid + 1;
}
if(nums[mid] == target) idx = mid;
}
return idx;
}
private int findLast(int[] nums, int target){
int idx = -1;
int start = 0;
int end = nums.length - 1;
while(start <= end){
int mid = (start + end) / 2;
//標記2,在思路里說
if(nums[mid] <= target){
start = mid + 1;
}else{
end = mid - 1;
}
if(nums[mid] == target) idx = mid;
}
return idx;
}
}
補充
不算補充吧,算總結收獲 (*?????)?。
這題讓我知道了二分法還有這種細節的玩法,可以在數字重復的時候準確取得首位和末尾~