題目描述:
給定一個按照升序排列的整數數組 nums,和一個目標值 target。找出給定目標值在數組中的開始位置和結束位置。
你的算法時間複雜度必須是 O(log n) 級別。
如果數組中不存在目標值,返回 [-1, -1]。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array
著作權歸領釦網絡所有。
栗子1:
輸入: nums = [5,7,7,8,8,10], target = 8
輸出: [3,4]
栗子2:
輸入: nums = [5,7,7,8,8,10], target = 6
輸出: [-1,-1]
思路:
看到題目之後,你最先想到的可能是for循環去遍歷,可是本題對時間複雜度有一定的要求,所以此路不通。
時間複雜度必須是O(log n) ,再加上數據結構是升序排列的數組,那麼很容易就聯想到二分查找算法了。有沒有“柳暗花明又一村”的感覺呢?
不過讀完題之後,你會發現這和我們當初學習的二分查找還不太一樣。當初二分查找返回的是目標值所在數組對應的下標,不存在則返回-1。所以呢,本題是二分查找的一個變形題目。如果你不清楚最基礎的二分查找,可以先去看一下資料,之後再看這道題就會事半功倍。
這裏呢,我認爲你已經瞭解了二分查找算法,所以主要來講一下尋找目標值的一些情況。數組的默認值最後說明哈,我們先從中間值左面的檢索說起。中間值爲mid,前一個元素就是mid-1,當mid-1=0的時候說明mid前面是有值的,屬於需要檢索的範圍,如果mid-1<0,那麼便超出了邊界,可以終止檢索。因爲我們要找的是目標值第一次出現的位置,所以值需要等於目標值,在滿足這兩個條件的情況下進行檢索。從中間值向右的檢索也是一個道理。如果檢索的過程中,發現了目標值,那麼皆大歡喜。我們把它放到結果數組中即可,可是要是沒找到怎麼辦呢?
如果中間值的左面和右面都沒有目標值,那麼我們返回什麼呢?當然是{mid,mid}了,爲什麼?因爲只有nums[mid]==target目標值的時候纔會走進這個else語句,而且只有一個目標值。就好像{1,2,3},target=2;也有可能左面會有返回值,右面沒有,就像{0,2,2,3,4},target=2;也有可能右面會有返回值,左面沒有,就像{0,1,2,2,3},target=2。這樣子是不是就可以想通了?
如果有什麼錯誤或者問題,歡迎評論,我們一起探討,一起進步。
代碼:
public static int[] searchRange(int[] nums, int target) {
int low = 0;
int high = nums.length - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (nums[mid] < target) {
low = mid + 1;
} else if (nums[mid] > target) {
high = mid - 1;
} else {
//注意
int[] a = {mid, mid};
//中間值向左檢索(不包含中間值)
int tmp = mid - 1;
while (tmp >= 0 && nums[tmp] == target) {
a[0] = tmp;
tmp--;
}
//中間值向右檢索(不包含中間值)
tmp = mid + 1;
while (tmp <= nums.length - 1 && nums[tmp] == target) {
a[1] = tmp;
tmp++;
}
//最終結果
return a;
}
}
return new int[]{-1, -1};
}