LeetCode35. 搜索插入位置 --(數組)--二分法查找-- 簡單

解題思路 

經典的二分法查找,通過題目解析可知查找的元素位置爲:查找中間值大於等於目標值的第一個元素索引

參考[1]

//java
class Solution 
{

    public int searchInsert(int[] nums, int target) 
    {
        int len = nums.length;
        if (nums[len - 1] < target) 
        {
            return len;
        }

        int left = 0;
        int right = len - 1;

        while (left <= right)
        {
            int mid = (left + right) / 2;
            // 等於的情況最簡單,我們應該放在第 1 個分支進行判斷
            if (nums[mid] == target) 
            {
                return mid;
            } 
else if (nums[mid] < target) 
            {
                // 題目要我們返回大於或者等於目標值的第 1 個數的索引
                // 此時 mid 一定不是所求的左邊界,
                // 此時左邊界更新爲 mid + 1
                left = mid + 1;
            } 
else 
{
                // 既然不會等於,此時 nums[mid] > target
                // mid 也一定不是所求的右邊界
                // 此時右邊界更新爲 mid - 1
                right = mid - 1;
            }
        }
       // 注意:一定得返回左邊界 left,
        // 如果返回右邊界 right 提交代碼不會通過
        // 【注意】下面我嘗試說明一下理由,如果你不太理解下面我說的,那是我表達的問題
       // 但我建議你不要糾結這個問題,因爲我將要介紹的二分查找法模板,可以避免對返回 left 和 right 的討論

     // 理由是對於 [1,3,5,6],target = 2,返回大於等於 target 的第 1 個數的索引,此時應該返回 1
        // 在上面的 while (left <= right) 退出循環以後,right < left,right = 0 ,left = 1
        // 根據題意應該返回 left,
        // 如果題目要求你返回小於等於 target 的所有數裏最大的那個索引值,應該返回 right

        return left;
    }
}

算法複雜度分析:

時間複雜度:O(logN) 原因是數組長度N每次劃分爲一半,2^x=N 求解x可得出

空間複雜度:O(1)

使用二分法模板:

二分查找的改進以及相關的題型

把if (nums[mid] == target) 的語句省略,首先第一步判斷目標值是否能包含在左右邊界之中,找出左右邊界。若不能包含在左右邊界之中,最後通過二分法排除只剩下的最後一個元素(夾逼法)還要做最後一次判斷,以判斷目標值是否和最後剩下的值相等。

第二步是  依據題目寫出中位數排除的判斷分支  left=mid+1

第三步是  對應的中位數不能排除的分支  right=mid

或者第二步和第三步顛倒過來

第二步  right=mid-1  第三步 left=mid

第四步返回left或者right即可。

注意偶數時:左中位數和右中位數的區分選擇(通過最後剩下兩個元素時判斷)。以避免死循環

//java
class Solution 
{

    public int searchInsert(int[] nums, int target) 
    {

       int len = nums.length;
        if (len == 0) 
        {
            return -1;
        }
        if (nums[len - 1] < target) 
        {
            return len;
        }
        int left = 0;
        int right = len - 1;
        //排除上述特殊情況後,依據題目可以確定目標值一定在在左右邊界之中
        while (left < right) 
        {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) //依據題目排除中位數(此判斷中位數小於目標值,而題目要找的是大於或等於目標值的第一個元素)
            {
                // nums[mid] 的值可以捨棄
                left = mid + 1;
            } 
            else //中位數大於或等於目標值
            {
                // nums[mid] 不能捨棄
                right = mid;
            }
        }
        //循環結束只剩下最後一個值
        return right;
    }

}

 總結該模板和普通二分法的差別在於:

1)去掉了中間值的判斷等於,新的模板在最後會得到最後一個數

2)在該模板中需要確定要找的元素是否包含在邊界內(left  right)若不在則最後得到的元素要再做一次判斷

3)新模板最後返回的left=right

4)排除中位數的寫法有兩種,兩種寫法要注意的問題是:左中位數和右中位數的選擇不同的寫法不同,注意不然容易溢出

參考資料

【1】二分法的解題模板https://leetcode-cn.com/problems/search-insert-position/solution/te-bie-hao-yong-de-er-fen-cha-fa-fa-mo-ban-python-/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章