35. 搜尋插入位置(C++)
阿新 • • 發佈:2020-12-30
目錄
題目
給定一個排序陣列和一個目標值,在陣列中找到目標值,並返回其索引。如果目標值不存在於陣列中,返回它將會被按順序插入的位置。
你可以假設陣列中無重複元素。
示例 1:
輸入: [1,3,5,6], 5
輸出: 2
示例 2:
輸入: [1,3,5,6], 2
輸出: 1
示例 3:
輸入: [1,3,5,6], 7
輸出: 4
示例 4:
輸入: [1,3,5,6], 0
輸出: 0
分析與題解
暴力遍歷
我們直接遍歷給定排序陣列nums
中查詢val
值,大致會出現三種情況:
- 陣列中找到目標元素,因為陣列中不存在重複元素
- 陣列中找不到目標元素,且存在元素大於目標值,首位大於目標值的下標就是插入的目標下標
- 陣列中找不到目標元素,且所有元素都小於目標值,直接將目標值插入到陣列的末尾
nums.size()
經過上述討論,我們可以將第二、三情況判斷條件歸結到一起:對於排序陣列,只要當nums[i] >= val
,我們就可以返回當前下標。
完整程式碼如下:
class Solution { public: int searchInsert(vector<int>& nums, int target) { int num = nums.size(); for (int i = 0; i < num; i++) { if (nums[i] >= target) return i; } // 退出迴圈後則直接在陣列末尾插入元素 return num; } };
二分查詢(左閉右開)
注意右區間為開區間,所以初始化左右邊界時,右邊界可以賦值為陣列的長度
實際上該下標是越界的,無法訪問到
int left = 0, right = nums.size();
然後求取中值時取左中值,並且需要注意防止溢位:
int mid = left + (right - left) / 2;
對於中值下標我們與目標值進行比較:
- 當
nums[mid] == target
,我們直接返回中值下標 - 當
nums[mid] < target
,哪怕target不在陣列中,需要進行插入也不可能插入到當前位置,我們直接向後移位。那麼target值可能的取值區間變為[mid + 1, right)
- 當
nums[mid] > target
,此時不確定中值下標對應元素是否為首位大於目標值的元素,該下標有可能成為插入元素下標,需要進行保留。那麼target值可能的取值區間變為[left, mid)
完整程式碼如下:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0, right = nums.size();
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid;
}
return left;
}
};
二分查詢(左閉右閉)
注意討論的區間為左閉右閉區間,所有右邊界的初始下標必須是確實能夠進行訪問的:
int left = 0, right = num - 1;
關於中值的計算方式類似,但是因為是閉區間,無論nums[mid]
與target
關係如何,都需要對中值mid進行加(減)一操作。
因為雙閉區間的迴圈判斷條件為while (left <= right)
,所以退出while迴圈後左右邊界的關係為left = right + 1
,總共可分為四種情況進行討論:
- 當陣列中存在目標元素,即
nums[mid] == target
,那麼迴圈中就可以返回目標下標 - 當陣列中不存在目標元素:
- 當目標元素大於陣列中所有元素,此時迴圈時右邊界不會改變,左邊界會一直向右移動,退出迴圈的區間為[nums.size() , nums.size() - 1]
- 當目標元素小於陣列中所有元素,此時迴圈時左邊界不會改變,右邊界會一直向左移動,退出迴圈的區間為[0, -1]
- 當目標元素在取值在陣列所有元素之間時,此時迴圈的左/右邊界都會改變,退出迴圈的區間為[targetIndex, targetIndex - 1]
綜上討論,退出迴圈後關於插入元素下標的選擇,要麼選擇left
,要麼選擇right + 1
。
完整程式碼如下:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int num = nums.size();
int left = 0, right = num - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return right + 1;
}
};