陣列:二分法一看就會,一寫就廢
阿新 • • 發佈:2020-12-15
技術標籤:資料結構與演算法二分法資料結構演算法leetcode
陣列:二分法一看就會,一寫就廢
35. 搜尋插入位置
思路:
陣列有序,且不含重複元素,這就是使用二分查詢的重要前提,因為一旦有重複元素,使用二分查詢返回的元素下標並不是唯一的。
二分查詢涉及的很多的邊界條件,是 while(left < right) 還是 while(left <= right),到底是right = middle呢,還是要right = middle - 1呢?
第一種寫法:[left,right]
class Solution {
public:
int searchInsert (vector<int>& nums, int target) {
int n = nums.size();
int left = 0;
int right = n - 1; // 定義target在左閉右閉的區間裡,[left, right]
while (left <= right) { // 當left==right,區間[left, right]依然有效
int middle = left + ((right - left) / 2);// 防止溢位 等同於(left + right)/2
if (nums[middle] > target) {
right = middle - 1; // target 在左區間,所以[left, middle - 1]
} else if (nums[middle] < target) {
left = middle + 1; // target 在右區間,所以[middle + 1, right]
} else { // nums[middle] == target
return middle;
}
}
// 分別處理如下四種情況
// 目標值在陣列所有元素之前 [0, -1]
// 目標值等於陣列中某一個元素 return middle;
// 目標值插入陣列中的位置 [left, right],return right + 1
// 目標值在陣列所有元素之後的情況 [left, right], return right + 1
return right + 1;
}
};
時間複雜度:O(logn)
空間複雜度:O(1)
第二種寫法:[left,right)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0;
int right = n; // 定義target在左閉右開的區間裡,[left, right) target
while (left < right) { // 因為left == right的時候,在[left, right)是無效的空間
int middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
right = middle; // target 在左區間,在[left, middle)中
} else if (nums[middle] < target) {
left = middle + 1; // target 在右區間,在 [middle+1, right)中
} else { // nums[middle] == target
return middle; // 陣列中找到目標值的情況,直接返回下標
}
}
// 分別處理如下四種情況
// 目標值在陣列所有元素之前 [0,0)
// 目標值等於陣列中某一個元素 return middle
// 目標值插入陣列中的位置 [left, right) ,return right 即可
// 目標值在陣列所有元素之後的情況 [left, right),return right 即可
return right;
}
};
總結:
在二分查詢中,堅持迴圈不變數的原則,弄不清楚主要是因為對區間的定義沒有想清楚。