在排序數組中查找元素的第一個和最後一個位置(middle)
一、題目
LeetCode 34.在排序數組中查找元素的第一個和最後一個位置
給定一個按照升序排列的整數數組 nums
,和一個目標值 target
。找出給定目標值在數組中的開始位置和結束位置,如果數組中不存在目標值 target,返回 [-1, -1]。
你可以設計並實現時間複雜度爲 O(log n)
的算法解決此問題嗎?
示例 1:
輸入:nums = [5,7,7,8,8,10], target = 6
輸出:[-1,-1]
示例 2:
輸入:nums = [5,7,7,8,8,10], target = 8
輸出:[3,4]
提示:
- nums 是一個非遞減數組
二、基礎模版 III
因爲我們的判斷區間最少爲2個元素,所以我們要注意循環的執行條件
- 簡單的判斷邊界:
nums.length === 0,return -1
; - 定義初始的左右邊界:
left = 0, right = nums.length - 1
; - 確定執行條件:
left + 1 < right
,這也意味着查找區間要存在 3 個元素; - 向左查找時:
right = mid
; - 向左查找時:
left = mid
; - 判斷剩下的兩個元素哪個符合目標元素,並返回結果;
三、題解
分析模版
- 我們的目標是:尋找目標值的起始下標和終止下標,但它是可能重複的
- 針對這樣的情況,我們要將判斷拆解成查找目標首次出現的位置,和最後一次出現的位置\
- 我們講一個大問題,用拆分成2個小問題,並用二分但解決對應的問題
var searchRange = function(nums, target) {
const NO_TARGET = [-1, -1];
if (nums.length === 0) return NO_TARGET;
// 判斷首次位置
let firstPosition = findFirstPos(nums, target);
if (firstPosition < 0) return NO_TARGET;
// 獲取最終出現位置
let lastPostion = findLastPos(nums, target);
return [firstPosition, lastPostion];
};
// 首次出現目標位置,參考模板II
const findFirstPos = function(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left < right) {
let mid = left + ((right - left) >> 1);
if (nums[mid] === target) {
right = mid; // 捨棄右側,留mid,不管右側是否有重複值,我們只留1個滿足條件的
} else if (nums[mid] > target) {
right = mid - 1; // 直接捨棄
} else {
left = mid + 1; // 直接捨棄
}
}
if (nums[left] === target) return left;
return -1;
}
// 首次出現目標位置,參考模板II
const findLastPos = function(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left < right) {
let mid = left + ((right - left + 1) >> 1); // 注意這裏 + 1是爲了向上取整,因爲我們要查找最後出現的元素
if (nums[mid] === target) {
left = mid; // 捨棄右側,留mid
} else if (nums[mid] > target) {
right = mid - 1; // 直接捨棄
} else {
left = mid + 1;
}
}
if (nums[left] === target) return left;
return -1;
}
四、寫在最後
本文是二分查找-模版III
的第一題,後面的幾道題的也算是本模版的微調版,加油~
如果對你有所幫助不妨給本項目的github 點個 star,這是對我最大的鼓勵
關於我
- 花名:餘光
- WX:j565017805
- 沉迷 JS,水平有限,虛心學習中
其他沉澱
````