1. 程式人生 > 其它 >陣列:二分法一看就會,一寫就廢

陣列:二分法一看就會,一寫就廢

技術標籤:資料結構與演算法二分法資料結構演算法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;
    }
};

總結:
在二分查詢中,堅持迴圈不變數的原則,弄不清楚主要是因為對區間的定義沒有想清楚。