[アルゴリズム叩き日記] day10——704. 二分探索 34. ソートされた配列内の要素の最初と最後の位置を見つける

 

 704. 二分探索 

704. 二分探索

トピックの説明: 

n 要素のソートされた (昇順) 整数配列 nums とターゲット値を 指定して 、ターゲット値が存在する場合はインデックス  を返し 、そうでない場合は を返すtarget  関数を作成します 。 numstarget-1

問題解決のアイデア: 

この質問の配列は順序付けされており、2 つにセグメント化されているため、バイナリ アルゴリズムを使用してこの問題を解決できます。

左右が中央に移動し続ける場合、左右が同じ位置を指す可能性があり、この位置を判断する必要があるため、ループ条件は left<=right であることに注意してください。

 解決策コード:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;
        while(left<=right)
        {
            int mid=left+(right-left)/2;
            if(nums[mid]==target) return mid;
            if(nums[mid]>target) right=mid-1;
            if(nums[mid]<target) left=mid+1;
        }
        return -1;
        }
};

 34. ソートされた配列内の要素の最初と最後の位置を検索します

34. ソートされた配列内の要素の最初と最後の位置を検索します

 トピックの説明:

降順でない整数の配列 numsと目標値が 与えられますtarget配列内の指定されたターゲット値の開始位置と終了位置を見つけてください。

ターゲット値が配列内に存在しない場合に target返します [-1, -1]

時間計算量が の O(log n) アルゴリズムを設計して実装する必要があります。

問題解決のアイデア:

この問題では、二等分を使用して左右の端点の問題を解決します。まず、左と右が存在する必要があります。

例を通してこの質問を理解しましょう: [1,2,3,3,3,4,5]

左のエンドポイントを見つけます。ここでは、ターゲットの代わりに t を使用します (これは説明しやすいです)。

  • 二値思考操作: 上の例を 2 つの部分に分けることができます。今は左端を探しているため、例を [[1,2 ] [3,3,3,4,5] ]に分けることができます。

  1. x<t の場合、区間 [1,2] 内にあり、left=mid+1
  2. x>=t の場合、区間 [3,3,3,4,5] 内にあり、right=mid (ここでは、mid=0 の場合、right=-1 が出力されるため、mid-1 に等しくすることはできません)境界の)
  • 詳細:

ループ条件:

  1. 左<右     
  2. 左<=右   ×

どれを選びますか?話し合いましょう:

  1. 結果はあります
  2. すべて t (t1) より大きく、右は左に進み、最後に右は左で終わります。左 <= 右の場合、無限ループが発生します。
  3. すべて t (t2) 未満で、左は右に進み、最終的に左は右の右で終わります。

このことから、最初のオプションのみを選択できますが、2 番目のオプションは選択できません。

中間操作を見つけます。

  1. 左+(右-左)/2         ×
  2. 左+(右-左+1)/2    

極端なケースを考えて調べてみましょう!要素が 2 つだけ残っている場合:

1つ目のタイプでは問題ありませんが、2つ目のタイプではmid=0+2/2=1となり、left+1の演算を行うと範囲外イベントが発生します。

適切なエンドポイントを見つけます

  • 二値思考操作: 上の例を 2 つの部分に分割できます。左側のエンドポイントを探しているため、例を [ [1,2,3,3,3 ] . [ 4,5] ]に分割できます。

  1. x<=t の場合、区間 [1,2,3,3,3] 内にあり、left=mid
  2. x>t の場合、区間 [4,5] にあり、right=mid-1
  • 詳細:

ループ条件:

  1. 左<右     
  2. 左<=右   ×

または、左<右を選択します

中間操作を見つけます。

  1. 左+(右-左)/2        
  2. 左+(右-左+1)/2     ×

極端なケースを考えて調べてみましょう!要素が 2 つだけ残っている場合:

前者の場合、mid=0+1/2=0 の場合、right=mid-1 は範囲外になりますが、後者の場合は問題ありません。

解決策コード:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        //特殊情况处理一下
        if(nums.size()==0)return {-1,-1};
        int left=0,right=nums.size()-1;
        vector<int> ret;
        //查找左端点
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(nums[mid]<target)left=mid+1;
            if(nums[mid]>=target)right=mid;
        }
        //当left==right时就是结果
        if(nums[left]!=target)return {-1,-1};
        else ret.push_back(left);
        //查找右端点
        left=0,right=nums.size()-1;
        while(left<right)
        {
            int mid=left+(right-left+1)/2;
            if(nums[mid]<=target)left=mid;
            if(nums[mid]>target)right=mid-1;
        }
        if(nums[right]!=target)return {-1,-1};
        else ret.push_back(right);
        return ret;
    }
};

 

おすすめ

転載: blog.csdn.net/m0_69061857/article/details/133323980