C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で回転ソート配列の最小値を二分探索で効率的に見つける方法

ある配列が昇順にソートされているとします。しかし、この配列は私たちには未知のピボット(基準点)を軸に回転されています。このような回転ソート配列の中から最小値を見つける必要があります。例えば、配列が [3,4,5,1,2] の場合、出力は 1 となります。

解決のためのアプローチ:二分探索

この問題は二分探索(バイナリサーチ)を応用することで効率的に解けます。単純な線形探索では O(n) の計算量がかかりますが、回転ソート配列では必ずどちらか片側の半分がソート済みになっているという性質を利用すると、計算量を O(log n) まで抑えられます。

アルゴリズムの手順

  • low := 0high := 配列の最後のインデックスn := 配列のサイズans := 無限大(INT_MAX) として初期化します。
  • low <= high の間、以下を繰り返します。
    • mid := low + (high - low) / 2 として中央のインデックスを求めます。
    • arr[low] < arr[mid] の場合:左半分はソート済みなので、ansarr[low] の小さい方を ans に代入し、low := mid + 1 とします。
    • arr[high] > arr[mid] の場合:右半分はソート済みなので、ansarr[mid] の小さい方を ans に代入し、high := mid - 1 とします。
    • low == mid の場合:ansarr[low] の小さい方を ans に代入し、low := mid + 1 とします。
    • high == mid の場合:ansarr[high] の小さい方を ans に代入し、high := mid - 1 とします。
  • 最終的に ans を返します。

それでは、以下の実装例を見て理解を深めましょう。

実装例

#include <bits/stdc++.h>
using namespace std;
class Solution {
    public:
    int findMin(vector<int>& arr) {
        int low = 0;
        int high = arr.size() - 1;
        int n = arr.size();
        int ans = INT_MAX;
        while(low <= high){
            int mid = low + (high - low) / 2;
            if(arr[low] < arr[mid]){
                ans = min(ans, arr[low]);
                low = mid + 1;
            } else if(arr[high] > arr[mid]) {
                ans = min(ans, arr[mid]);
                high = mid - 1;
            } else if(low == mid) {
                ans = min(ans, arr[low]);
                low = mid + 1;
            } else if(high == mid) {
                ans = min(ans, arr[high]);
                high = mid - 1;
            }
        }
        return ans;
    }
};
main(){
    Solution ob;
    vector<int> v = {15,35,85,96,5,6,8,12};
    cout << ob.findMin(v);
}

入力

[15,35,85,96,5,6,8,12]

出力

5

計算量について

このアルゴリズムの時間計算量は O(log n) です。各反復処理で探索範囲が半分に絞られていくため、配列のサイズが大きくなっても高速に動作します。空間計算量は追加のデータ構造を使用しないため O(1) です。


  1. C++で (x % k) × (x / k) == n を満たす最小の x を求める方法

    2つの正の整数 n と k が与えられたとき、(x % k) × (x / k) が n と等しくなるような正の整数 x を求める必要があります。例えば n = 4、k = 6 の場合、答えは 10 になります。実際に確認すると、(10 % 6) × (10 / 6) = 4 × 1 = 4 となり、条件を満たしています。解法のアプローチここでポイントになるのは、x % k の値が必ず 1 以上 k − 1 以下の範囲に収まるという点です(0 は除外します。x % k が 0 になると積も 0 になり、正の整数 n とは一致しないためです)。そこで、n の約数のうち [1, k − 1] の範

  2. C++で回転ソート済み配列の回転回数を求める方法

    ここでは、回転ソート済み配列(Rotated Sorted Array)が与えられたときに、その配列を元のソートされた状態に戻すために必要な回転回数を求める問題を扱います。なお、回転は「右から左へ」要素を移動させる操作として考えます。例えば、次のような配列を考えてみましょう。{15, 17, 1, 2, 6, 11}この配列をソートするには、2回の回転が必要です。回転を繰り返すと、最終的に次の順序になります。{1, 2, 6, 11, 15, 17}この場合の出力(回転回数)は 2 となります。解法のポイントこの問題のロジックは非常にシンプルです。配列を注意深く観察すると、必要な回転回数は「最