34.給你一個按照非遞減順序排列的整數數組 nums,和一個目標值 target。請你找出給定目標值在數組中的開始位置和結束位置。
如果數組中不存在目標值 target,返回 [-1, -1]。
你必須設計并實現時間復雜度為 O(log n) 的算法解決此問題。
示例 1:
輸入:nums = [5,7,7,8,8,10], target = 8
輸出:[3,4]
示例 2:
輸入:nums = [5,7,7,8,8,10], target = 6
輸出:[-1,-1]
示例 3:
輸入:nums = [], target = 0
輸出:[-1,-1]
- 非遞減數組求區間,很容易想到的是兩次二分查找找到左右邊界。由于左右邊界的找法幾乎相同,所以把題目轉換一下,只要找到 target 的右邊界,我們就知道了結束位置為右邊界 - 1;而開始位置,我們只要知道 target - 1 的右邊界即可,因為是整數數組,所以只要 target 在數組中存在,那么剛剛大于 target - 1(也就是右邊界) 的肯定是 target。這樣的話我們只需要把二分查找右邊界寫成方法,最終返回大致為
[solve(target-1),solve(target)-1]
即可。剩下的就是分析區間不存在的情況。首先數組沒數肯定就直接返回了,其次如果我能找到區間。那么可以肯定的是,nums[開始位置] 一定是等于 target 的,不是的話肯定也返回了。還有就是如果所有數都比 target 小,那么起始位置會找到數組外面去,所以二分查找返回的數組下標也應當合法。 -
public int[] searchRange(int[] nums, int target) {if(nums.length == 0){return new int[]{-1,-1};}int first = solve(nums,target-1);// 需要先判斷 first 是否合法,否則 nums[first] 可能直接數組越界了if(first >= nums.length || nums[first] != target){return new int[]{-1,-1};}return new int[]{first,solve(nums,target)-1};}public int solve(int[] nums,int target){int left=0,right=nums.length-1;while(left<=right && left >=0 && right <= nums.length-1){int mid = (left+right)/2;// 這里用小于等于,那么左邊界就會不斷右移,直到找到大于 target 的第一個數// 所以這里的 left 最后就是 target 的右邊界,如果用小于就是左邊界了if(nums[mid]<=target)left=mid+1;else right=mid-1;}return left;}