LeetCode34要素の最初と最後の解を見つける

質問の詳細

昇順で配置された整数配列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]、ターゲット= 6
出力:[-1、-1]

この質問を書く目的は、二分法の能力を行使することです。したがって、結局のところ、logNをさらに書く必要があります。
第二に、この質問のサブ問題は非常に役立つ質問になる可能性があります。

分析と回答

質問のアイデアはこのように書くことができます

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

ここでは、バイナリ検索を使用して、左右の間隔で最初と最後のターゲットを検索するため、合計はlogNになります。
私の書き方の利点は、最初のものを見つけて最後のものを直接見つけるlogNよりも少し小さいことですが、大きさの順序は同じです。

最初と最後のものを見つけるアイデアについては、コードを直接見てください

	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;//未找到
    }

ここで最後に見つかったものは、上記のアイデアと一致していますが、少し変更するだけです。
実際、上記は以下の質問に使えると思います。結局、logNは最初か最後かを見つけますが、それでも練習する必要があります。

全体的なコードは次のとおりです。

	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