ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

二分法查找

2021-04-10 10:00:31  阅读:151  来源: 互联网

标签:high nums int 复杂度 mid 二分法 查找 low


整理了一下最近三天的力扣题,都是和二分法相关的。
首先我们应知道,使用二分法的前提就是数组有序,但是这三题都是将一个原本非降序的数组旋转后得到一个两部分都有序的数组,增加了点难度。
我们一个一个来看:
在这里插入图片描述
题解给了一张图,我觉得很便于理解,旋转后的数组是这样
在这里插入图片描述
我们要想找最小值,我们可以先取一个low代表左端点,一个high代表右端点,然后mid=low+high/2,如果nums[mid]<nums[high],说明最小值在mid或者mid左边,我们可以舍弃右半段,如果nums[mid]>nums[high],说明最小值在mid右边,我们可以舍弃左半段,当low==high时,我们就退出,此时nums[low]对应的就是最小值,因为不存在重复元素,所以不存在nums[mid]==nums[high]的情况,时间复杂度是O(logn),空间复杂度O(1)。
具体代码如下:

class Solution {
    public int findMin(int[] nums) {
        int low=0,high=nums.length-1;
        while(low<high){
            int mid=(low+high)/2;
            if(nums[mid]<nums[high]){
                high=mid;
            }else{
                low=mid+1;
            }
        }
        return nums[low];

    }
}

再看第二题:
在这里插入图片描述
这一题和上一题有一点不同,就是数组里可以有重复元素了,所以就多了一种情况nums[mid]==nums[high],题解又给了一张图,很便于理解
在这里插入图片描述
图中的pivot就是mid的意思,当nums[mid]==nums[high]时,我们无法确定最小值在左半段还是右半段,但是我们可以确定最右边的边界可以去掉,因为至少mid的值和他一样小,所以就可以将右边界-1,平均时间复杂度是O(logn),最坏时间复杂度O(n),空间复杂度O(1)。
代码如下:

class Solution {
    public int findMin(int[] nums) {
        int low=0,high=nums.length-1;
        while(low<high){
            int mid=(low+high)/2;
            if(nums[mid]<nums[high]){
                high=mid;
            }else if(nums[mid]>nums[high]){
                low=mid+1;
            }else{
                high--;
            }
        }
        return nums[low];

    }
}

来看最后一题
在这里插入图片描述
这题和前两题不太一样,他可以有重复元素,而且他不是找最小值,而是找是否存在目标值,虽然这题用了二分查找,但是因为不知道旋转后的具体位置,所以无法做到真正的二分查找,只能做到局部的二分查找,最坏情况下时间复杂度是O(n),空间复杂度O(1)。
这一题还可以用上一题的图
在这里插入图片描述
当我们用二分法查找时
有三种情况:
第一种nums[left]==nums[mid]==nums[right],这个时候无法判断目标值在哪半段,但是可知left和right已经不是目标值(自己判断,如果是就返回true结束了),所以左右端点可以同时缩进1
第二种nums[left]<=nums[mid],可知左半段有序,如果目标值在左半段,就在左半段搜索,否则在右半段搜索
第三种nums[left]>nums[mid] (其实等同于nums[mid]<=nums[right],即右半段有序),如果目标值在右半段,就在右半段搜索,否则在左半段搜索
代码如下:

class Solution {
    public boolean search(int[] nums, int target) {
        int n = nums.length;
        if (n == 0) {
            return false;
        }
        if (n == 1) {
            return nums[0] == target;
        }
        int l = 0, r = n - 1;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (nums[mid] == target) {
                return true;
            }
            if (nums[l] == nums[mid] && nums[mid] == nums[r]) {//左=中=右
                ++l;
                --r;
            } else if (nums[l] <= nums[mid]) {//左半段有序
                if (nums[l] <= target && target <= nums[mid]) {
                    r = mid ;
                } else {
                    l = mid + 1;
                }
            } else {//nums[l]>nums[mid] 右半段有序
                if (nums[mid] <= target && target <= nums[r]) {
                    l = mid ;
                } else {
                    r = mid - 1;
                }
            }
        }
        return false;

    }
}

标签:high,nums,int,复杂度,mid,二分法,查找,low
来源: https://blog.csdn.net/little_sun_513/article/details/115563589

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有