Java教程

浅析数组的二分查找

本文主要是介绍浅析数组的二分查找,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

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

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

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;
    }
}

 四、总结:

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

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

这篇关于浅析数组的二分查找的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!