特殊的二分查找法LeetCode(33)34(35)利用双指针进行特殊二分法的查找

问题为:给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]

具体思想为:

对于题目中的进阶要求中有再lgn时间内解决,因此首先考虑的就是二分法查找,首先基于如果数组中元素为升序排列,且数组中元素各不相同的情况下,首先设置循环判定条件while(left<=right)之后对于循环内的判定条件,先判断nums[mid]==target是否成立,若成立则直接return mid即可,若不成立,则判断nums[mid]>target是否成立,若成立则表明target可能在mid的左边区间(之所以为可能是因为target也可能不在nums数组内),则将区间大小缩小为左边区间的大小即令right=mid-1;若不满足nums[mid]>target即target>nums[mid]表明target可能在mid的右边区间内,于是要将整个的区间大小缩小为右边区间的大小即可,即为left=mid+1;之后对于缩小后的区间若仍然满足left<=right则继续执行循环的条件,否则则直接return -1;表明已经退出了循环即递增的数组内不存在target元素,故而返回-1。
上述是基于不存在重复元素的基础上的最基本的二分查找法,但是该问题的数组中允许元素是重复的,所以可以这样设置,设置两个函数public int Firstnum(int[] nums,int target)与public int Lastnum(int[] nums,int target)来确定该target的首个相等处的下标和最后一次相等处的下标,如实例为nums = [5,7,7,8,8,10], target = 8,对于Firstnum可以先直接按照最原始的二分法书写代码,但对于其中nums[mid]==target的情况要进行修改,即若满足该情况时,要判断mid==0或者nums[mid-1]!=nums[mid]是否成立,若二者有一个成立,则表明该mid一定就是首个相等处的下标例如实例中的下标3即为此种情况.如果不满足二者中的任意一种情况,即表明该target不是要寻找的数,要寻找的数一定在该mid的左侧区间,即缩小区间范围为该mid的左侧区间,即令right=mid-1;
同理对于Lastnum的情况类似于上方的Firstnum函数对于nums[mid]==target的情况,的判定双条件为mid==nums.length-1或nums[mid+1]!=nums[mid]即可,之后若不满足则表明要找的target则在该mid的右侧区间即要令left=mid+1即可实现.
具体代码实现如下所示。

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] ans=new int[2];
        int a,b;
        a=Firstnum(nums,target);
        b=Lastnum(nums,target);
        ans[0]=a;
        ans[1]=b;
        return ans;
    }
    public int Firstnum(int[] nums,int target){
        int left=0,right=nums.length-1;
        while(left<=right){
            int mid=left+(right-left)/2;
            if(nums[mid]==target){
                if(mid==0||nums[mid-1]!=nums[mid]){
                    return mid;
                }else{
                    right=mid-1;
                }
            }else if(nums[mid]<target){
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return -1;
    }
    public int Lastnum(int[] nums,int target){
        int left=0,right=nums.length-1;
        while(left<=right){
            int mid=left+(right-left)/2;
            if(nums[mid]==target){
                if(mid==nums.length-1||nums[mid+1]!=nums[mid]){
                    return mid;
                }else{
                    left=mid+1;
                }
            }else if(nums[mid]<target){
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return -1;
    }
}

对于一般的二分查找法要注意的是,如果目标target不在该升序的数组nums中,并且要插入该nums数组且仍保持数组nums为升序的则target要插入的下标应为left指针当前的值具体分析如下:

在执行完毕二分查找法后,要注意的是,对于找不到数的情况有三种极端1.如果目标target小于数组中所有的值,则left的值0一不会改变,最后要插入的位置也恰好为0故而返回left即可.2如果目标target大于数组中的所有元素,则right值一直不变最后情况为left指向倒数第二个数,right指向最后一个数,mid求出来为left的值,故而nums[mid]<target应执行left=mid+1,的操作即此时left的值为nums.length-1此也为target要插入的下标的值。3.如果查找的target不在该数组内但在该数组的两个数值之间的范围,则最终left与right一定分别指向该两个数,则按照情况2的分析,最后left一定会变成原来right的指针位置的值,因此这也是target应该插入的target所在的下标。故而结合上述三种情况,当target不在nums数组中时,目标值target如果要插入该数组中,则要插入的下标应为二分查找后的left的最后的值.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时光的样子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值