Given a sorted array of integers, 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),這是典型的二分查詢法的時間複雜度,所以這道題我們也需要用此方法,我們的思路是首先對原陣列使用二分查詢法,找出其中一個目標值的位置,然後向兩邊搜尋找出起始和結束的位置,程式碼如下:
解法一:
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { int idx = search(nums, 0, nums.size() - 1, target); if (idx == -1) return {-1, -1}; int left = idx, right = idx; while (left > 0 && nums[left - 1] == nums[idx]) --left; while (right < nums.size() - 1 && nums[right + 1] == nums[idx]) ++right; return {left, right}; } int search(vector<int>& nums, int left, int right, int target) { if (left > right) return -1; int mid = left + (right - left) / 2; if (nums[mid] == target) return mid; else if (nums[mid] < target) return search(nums, mid + 1, right, target); else return search(nums, left, mid - 1, target); } };
可能有些人會覺得上面的演算法不是嚴格意義上的O(logn)的演算法,因為在最壞的情況下會變成O(n),比如當陣列裡的數全是目標值的話,從中間向兩邊找邊界就會一直遍歷完整個陣列,那麼我們下面來看一種真正意義上的O(logn)的演算法,使用兩次二分查詢法,第一次找到左邊界,第二次呼叫找到右邊界即可,具體程式碼如下:
解法二:
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { vector<int> res(2, -1); int left = 0, right = nums.size() - 1; while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] < target) left = mid + 1; else right = mid; } if (nums[right] != target) return res; res[0] = right; right = nums.size(); while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] <= target) left = mid + 1; else right= mid; } res[1] = left - 1; return res; } };
參考資料:
https://discuss.leetcode.com/topic/19437/the-standard-and-clean-c-binary-search-implementation