栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

数组双指针之二分搜索(一)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数组双指针之二分搜索(一)

1.在排序数组中查找元素的第一个和最后一个位置

leetcode34题
常规解法:for循环遍历有序序列,使用两个变量标记第一个数的位置和最后一个数位置。时间复杂度为O(n)。

进阶解法:使用二分搜索法搜索左右边界,时间复杂度O(logn)。
搜索左边界的方法:
1. 首先与正常二分搜索法一样,找到序列中与目标值相同的值;
2. 正常的二分搜索找到正常的值时退出循环即可,而搜索左边界不退出循环,令搜索区间的right等于该目标值的索引减1,收缩右侧边界。换句话来说是依次搜索目标值左侧区间中是否有与目标值相等的数;
3. 搜索右边界同理。

```Java
 public static int leftBound(int[] nums, int target) {
        //当有序序列为空时
        if(nums.length==0){
            return -1;
        }
        int left = 0;//定义左边界
        int right = nums.length - 1;//定义右边界
        while (left <= right) {
            int mid = left + (right - left) / 2;
            //搜索区间[left,mid-1]
            if (nums[mid] > target) {
                right = mid - 1;
            }
            //搜索区间[right,mid+1]
            else if (nums[mid] < target) {
                left=mid+1;
            }
            //搜索区间[left,mid-1]
            else if (nums[mid] == target) {
                right=mid-1;
            }
        }
        //检查目标值大于序列最大值和目标值小于序列最小值
        if (left >= nums.length || nums[left] != target)
            return -1;
        return left;
    }
    public static int rightBound(int[] nums, int target) {
        //当有序序列为空时
        if(nums.length==0){
            return -1;
        }
        int left = 0;//定义左边界
        int right = nums.length - 1;//定义右边界
        while (left <= right) {
            int mid = left + (right - left) / 2;
            //搜索区间[left,mid-1]
            if (nums[mid] > target) {
                right = mid - 1;
            }
            //搜索区间[right,mid+1]
            else if (nums[mid] < target) {
                left=mid+1;
            }
            //搜索区间[left,mid+1]
            else if (nums[mid] == target) {
                left=mid+1;
            }
        }
        //这里改写right越界条件,因为移动的是right
        if (right < 0 || nums[right] != target)
            return -1;
        return right;
    }
```

有了搜索左右边界我们就可以查找某个元素的第一个和最后一个元素。时间时间复杂度O(logn)。到这里我就把二分搜索的三种类型都介绍给大家了。

注意:二分搜索其实有很多中写法,有左开右闭区间,左闭右开区间,但我还是建议大家按我一样只写左闭右闭统一成一种形式,这样代码很好记,while循环的判断条件left《right,以后闭着眼睛都可以写出来。

2.二分查找

leetcode704题

要求:给定n个元素的升序整型数组和一个目标值,返回目标值下标,不存在返回-1。
解题思路:这道题其实在上面已经做过了,二分搜索的进阶我们都可以闭住眼睛写出来,这道题当然不在话下,在找到目标值的时候返回即可。

```Java
public static int binarySearch(int[] nums, int target) {
        //当有序序列为空时
        if(nums.length==0){
            return -1;
        }
        int left = 0;//定义左边界
        int right = nums.length - 1;//定义右边界
        while (left <= right) {
            int mid = left + (right - left) / 2;
            //搜索区间[left,mid-1]
            if (nums[mid] > target) {
                right = mid - 1;
            }
            //搜索区间[right,mid+1]
            else if (nums[mid] < target) {
                left=mid+1;
            }
            //搜索区间[left,mid+1]
            else if (nums[mid] == target) {
                return mid;
            }
        }
        //不在搜索区间内直接返回-1即可,不需要判断左右指针越界
            return -1;
    }
```
3.搜索插入位置

leetcode35题
要求:给定⼀个排序数组和⼀个⽬标值,在数组中找到⽬标值,并返回其索引。如果⽬标值不存在于数组中,返回它将会被按顺序插⼊的位置。

解题思路:这道题就是考察搜索左侧边界的二分算法的细节理解。当目标元素不存在数组中时,搜索左侧边界的二分搜索的返回值可以做以下几种解读:

1. 返回值是nums中大于等于target的最小元素索引;
2. 返回的值是target应该插入在nums中的索引位置;
3. 返回的这个值是 nums 中⼩于 target 的元素个数。
⽐如在有序数组 nums = [2,3,5,7] 中搜索 target = 4,搜索左边界的⼆分算法会返回 2,也就是5的索引,你带⼊上⾯的说法,都是对的。

所以以上三种解读都是等价的,可以根据具体题⽬场景灵活运⽤,显然这⾥我们需要的是第⼆种。 返回的值是nums中小于target的元素个数。

目标元素不存在数组中,右边界的解读也是一样的,有兴趣的同学可以自己试一试。

```Java
 public static int leftBound(int[] nums, int target) {
        //当有序序列为空时
        if(nums.length==0){
            return -1;
        }
        int left = 0;//定义左边界
        int right = nums.length - 1;//定义右边界
        while (left <= right) {
            int mid = left + (right - left) / 2;
            //搜索区间[left,mid-1]
            if (nums[mid] > target) {
                right = mid - 1;
            }
            //搜索区间[right,mid+1]
            else if (nums[mid] < target) {
                left=mid+1;
            }
            //搜索区间[left,mid-1]
            else if (nums[mid] == target) {
                right=mid-1;
            }
        }
        //检查目标值大于序列最大值和目标值小于序列最小值
        if (left >= nums.length || nums[left] != target)
            return -1;
        return left;
    }
```
4.总结

从上面的三道题中,二分搜索的三种基本类型都给出了,按照我的模板学习,闭着眼睛都可以写出来。有了二分的基础之后需要培养发现二分的能力,在以后的刷题中我们会经常遇到那种很难分解出二分的题。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/727756.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号