LeetCode 34 查找元素第一个与最后一个 题解

题目详情

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

你的算法时间复杂度必须是 O(log n) 级别。

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

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
示例 2:

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

写这题的目的,是为了锻炼自己的二分能力,二分还是要多写啊,毕竟logN。
其次,这题的子问题可以是非常有用的问题。

分析与解答

该题的思路可以写成这样

二分查找:
    如果nums[mid]>target :
    	则target在另一边
    如果nums[mid]<target :
    	则target在另一边
    如果nums[mid]==target:
    	则找到了目标值,于是便来寻找其第一个与第二个
    	在左区间find第一个target
    	在右区间find最后的target
    	return
    
    return

这里,在左右区间find第一个与最后一个target都是用的二分查找,所以总的都是logN。
我这种的写法的好处,是比直接上来就find第一个,find最后一个,的logN的N要小一点,不过数量级还是一致的。

关于find第一个和最后一个的思路直接看代码

	public int findFirstTarget(int[] nums,int target){
    
    
        int l = 0, r = nums.length-1;
        int mid = l + ((r-l)>>1);
        while(l<=r){
    
    
            if(nums[mid]>target){
    
    
                r = mid - 1;
            }
            else if(nums[mid]<target){
    
    
                l = mid + 1;
            }
            else{
    
    
                if(mid==l || nums[mid-1]!=target){
    
    
                    return mid;
                }
                r = mid - 1;
            }
            mid = l + ((r-l)>>1);
        }
        return -1;//未找到
    }

这里find最后一个和上述思路一致,稍作修改即可。
以上的其实感觉后面做题都可以用的到,毕竟logN查找到第一个or最后一个,还是有必要练习的。

整体的代码是:

	public int[] searchRange(int[] nums, int target) {
    
    
        //思路这样
        //首先二分查找,修改l与r
        //一旦mid找到,则两边分别找第一个target和最后一个target
        int l=0, r=nums.length-1;
        while(l<=r){
    
    
            int mid = l+ ((r-l)>>1);
            if(nums[mid]<target){
    
    
                l = mid+1;
            }
            else if(nums[mid]>target){
    
    
                r = mid-1;
            }
            else {
    
    
                //target==nums[mid],则左区间寻找第一个target,右区间寻找最后一个target
                //都是二分法查找
                int ll = l, lr = mid;
                int lmid = ll + ((lr-ll)>>1);
                while(ll<=lr){
    
    
                    if(nums[lmid]<target){
    
    
                        ll = lmid +1;
                    }
                    else{
    
    
                        if(lmid==ll || nums[lmid-1]!=target){
    
    
                            break;
                        }
                        lr = lmid -1;
                    }
                    lmid = ll + ((lr-ll)>>1);
                }

                int rl = mid, rr = r;
                int rmid = rl + ((rr-rl)>>1);
                while(rl<=rr){
    
    
                    if(nums[rmid]>target){
    
    
                        rr = rmid - 1;
                    }
                    else{
    
    
                        if(rmid==rr || nums[rmid+1]!=target){
    
    
                            break;
                        }
                        rl = rmid + 1;
                    }
                    rmid = rl + ((rr-rl)>>1);
                }
                return new int[]{
    
    lmid,rmid};
            }
        }
        return new int[]{
    
    -1,-1};
    }

猜你喜欢

转载自blog.csdn.net/qq_34687559/article/details/110001055