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-/

发布了136 篇原创文章 · 获赞 112 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/heda3/article/details/103946812