ICode9

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

浅析数组的二分查找

2021-12-16 22:58:41  阅读:122  来源: 互联网

标签:二分 right target nums int mid 查找 数组 浅析


说明:以下的所有内容都是来自个人对于二分查找使用情况的浅薄理解,仅供个人参考!不喜勿喷,欢迎大家来纠错!

一、适合二分查找的情况分为两大类:

1.明显的条件:

数组为有序的,并且明确告诉你数组的元素不会重复。

这种情况是一定能用二分查找的。

2.隐含的条件:

题目说明数组为:

非升序(意思是数组为整体降序,允许数组元素重复);

       例如: int[] array={9,8,8,6,5,4,3,2,1}

非降序(意思是数组整体为升序,允许数组元素重复);

       例如:int[]  array={0,1,1,2,3,4,5,6,6,6,7}

在这种情况下,我目前遇到得一个情况是下面的“例题2”  就可以用二分查找。

二、两种二分查找的方法:

1,左闭右闭区间型:

right为数组的长度-1,即数组下标可能访问到right;

left为0下标;

     在这种情况下,查找的target可能为边界情况,所以while()的循环条件就是 left<=right.

并且,当你的 array[mid]>target时,target以及target的右边是不存在target的,区间的边界情况是不变的,即仍是左闭右闭区间,

即   right=mid-1;

当你的array[mid]<target时,target以及target的左边是不存在target的,区间的边界情况也是不变的,仍是左闭右闭区间,

即   left=mid+1;

当满足array[mid]=target时,mid是target的下标,即返回mid;

2,左闭右开区间型:

right为数组的长度,即数组下标不可能访问到right;

left为0下标;

     在这种情况下,查找的target不可能为边界情况,所以while()的循环条件就是 left<right.

并且,当你的 array[mid]>target时,target以及target的右边是不存在target的,区间的边界情况是不变的,即仍是左闭右开区间,

即   right=mid;

当你的array[mid]<target时,target以及target的左边是不存在target的,区间的边界情况也是不变的,仍是左闭右开区间,

即   left=mid+1;

当满足array[mid]=target时,mid是target的下标,即返回mid;

3,具体实例:

连接:

https://leetcode-cn.com/problems/binary-search/

力扣上的题:二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

左闭右闭型解法:
 

class Solution {

    public static int search(int[] nums, int target) {

        int left=0;

        int right=nums.length-1;

        while(left<=right){

             int mid=left+(right-left)/2;

             if(nums[mid]>target){

                 right=mid-1;

             }else if(nums[mid]<target){

                 left=mid+1;

             }else{

                 return mid;

             }

        }

        return -1;

    }

}

左闭右开型解法:
 

class Solution {

    public static int search(int[] nums, int target) {

        int left=0;

        int right=nums.length; //   注意这里变了没有-1.

        while(left<right){   // 这里的循环条件没有等号

             int mid=left+(right-left)/2;

             if(nums[mid]>target){

                 right=mid;//这里本来就是取不到的数组长度值 不用-1;

             }else if(nums[mid]<target){

                 left=mid+1;

             }else{

                 return mid;

             }

        }

        return -1;

    }

}

三、二分查找的具体实战两道题:

1.对应一中的 1的情况:

连接:

https://leetcode-cn.com/problems/search-insert-position/

题目:

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

用例:

输入: nums = [1,3,5,6], target = 5
输出: 2
输入: nums = [1,3,5,6], target = 2
输出: 1
输入: nums = [1,3,5,6], target = 0
输出: 0

左闭右闭型解法:

class Solution {
    public static int searchInsert(int[] nums, int target) {
        int l=0;
        int r=nums.length-1;   //左闭右闭区间。
        while(l<=r){
            int mid=l+(r-l)/2;
            if(nums[mid]>target){
                r=mid-1;
            }else if(nums[mid]<target){
                l=mid+1;
            }else{
                return mid; // 处理了target 存在于数组里的情况
            }
        }
        return r+1; // 处理了1.target在数组之前,2.target插入了数组中。3.target在数组最后边。
    }
}

左闭右开型解法:

class Solution {
    public static int searchInsert(int[] nums, int target) {
        //二分法第二种方法;
        int left=0;
        int right=nums.length; //左闭又开区间;
        while(left<right){
            int mid=left+(right-left)/2;
            if(nums[mid]>target){
                right=mid;
            }else if(nums[mid]<target){
                left=mid+1;
            }else{
                return mid;
            }
        }
        return right;
    }
}

2.对应一种的 2 的题:

连接:

https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/

题目:

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:

    你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?

用例:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

左闭又闭型解法:

class Solution {
    //先找>=target的第一个
    //再找>target的第一个
    //第一种解法
    public int[] searchRange(int[] nums, int target) {
        int l=searchFirst(nums,target);
        int r=searchFirst(nums,target+1);
        if(l==nums.length||nums[l]!=target){
            return new int[]{-1,-1};
        }
        return new int[]{l,r-1};
    }
    public int searchFirst(int[] nums,int target){
        int l=0;
        int r=nums.length;
        while(l<r){
            int mid=l+(r-l)/2;
            if(nums[mid]>=target){
                r=mid;
            }else{
                l=mid+1;
            }
        }
        return l;
    }
}

 左闭右开型解法:

class Solution {
    //先找>=target的第一个
    //再找>target的第一个
    //第二种解法
    public int[] searchRange(int[] nums, int target) {
        int l=searchFirst(nums,target);
        int r=searchFirst(nums,target+1);
        if(l==nums.length||nums[l]!=target){
            return new int[]{-1,-1};
        }
        return new int[]{l,r-1};
    }
    public int searchFirst(int[] nums,int target){
        int l=0;
        int r=nums.length-1;// 这里变了
        while(l<=r){
            int mid=l+(r-l)/2;
            if(nums[mid]>=target){
                r=mid-1;//这里变了
            }else{
                l=mid+1;
            }
        }
        return l;
    }
}

 四、总结:

       关于个人对于数组二分查找的总结就完了,欢迎大家指出错误。再次声明,这个博客只是个人粗浅的理解和总结,不喜勿喷!不喜勿喷!不喜勿喷! 重要事情说三遍!!!

       如果觉得此博客能帮到你,请关注支持一下,万分感谢》

标签:二分,right,target,nums,int,mid,查找,数组,浅析
来源: https://blog.csdn.net/qq_62844347/article/details/121985259

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

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

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

ICode9版权所有