704. 二分探索
トピックの説明:
n
要素のソートされた (昇順) 整数配列 nums
とターゲット値を 指定して 、ターゲット値が存在する場合はインデックス を返し 、そうでない場合は を返すtarget
関数を作成します 。 nums
target
-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] ]に分けることができます。
- x<t の場合、区間 [1,2] 内にあり、left=mid+1
- x>=t の場合、区間 [3,3,3,4,5] 内にあり、right=mid (ここでは、mid=0 の場合、right=-1 が出力されるため、mid-1 に等しくすることはできません)境界の)
- 詳細:
ループ条件:
- 左<右 √
- 左<=右 ×
どれを選びますか?話し合いましょう:
- 結果はあります
- すべて t (t1) より大きく、右は左に進み、最後に右は左で終わります。左 <= 右の場合、無限ループが発生します。
- すべて t (t2) 未満で、左は右に進み、最終的に左は右の右で終わります。
このことから、最初のオプションのみを選択できますが、2 番目のオプションは選択できません。
中間操作を見つけます。
- 左+(右-左)/2 ×
- 左+(右-左+1)/2 √
極端なケースを考えて調べてみましょう!要素が 2 つだけ残っている場合:
1つ目のタイプでは問題ありませんが、2つ目のタイプではmid=0+2/2=1となり、left+1の演算を行うと範囲外イベントが発生します。
適切なエンドポイントを見つけます。
- 二値思考操作: 上の例を 2 つの部分に分割できます。左側のエンドポイントを探しているため、例を [ [1,2,3,3,3 ] . [ 4,5] ]に分割できます。
- x<=t の場合、区間 [1,2,3,3,3] 内にあり、left=mid
- x>t の場合、区間 [4,5] にあり、right=mid-1
- 詳細:
ループ条件:
- 左<右 √
- 左<=右 ×
または、左<右を選択します
中間操作を見つけます。
- 左+(右-左)/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;
}
};