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

C++で配列を条件を満たす2つの部分配列に分割する方法

問題の概要

配列 A が与えられたとき、それを left と right という 2 つの部分配列に分割することを考えます。分割は以下の条件を満たす必要があります。

  • left 部分配列のすべての要素は、right 部分配列のすべての要素以下である
  • left と right はどちらも空であってはならない
  • left のサイズは可能な限り小さくする

このような分割を行った後の left の長さを求めます。なお、条件を満たす分割が存在することは保証されています。

例えば、入力が [5,0,3,8,6] の場合、出力は 3 になります。このとき left は [5,0,3]、right は [8,6] となるためです。

アルゴリズムの考え方

この問題は、接頭辞最大値(prefix max)と接尾辞最小値(suffix min)を組み合わせることで、効率的に解くことができます。手順は以下の通りです。

  1. n := A のサイズとし、サイズ n の配列 maxx を作成する
  2. minVal := A の最後の要素とする
  3. maxx[0] := A[0] とする
  4. i が 1 から n-1 までの範囲で、maxx[i] := max(A[i], maxx[i-1]) と更新する(maxx[i] は A[0..i] の最大値を表す)
  5. ans := A のサイズ - 1 で初期化する
  6. i を n-1 から 1 まで逆順に処理する
    • minVal := min(minVal, A[i]) と更新する(minVal は A[i..n-1] の最小値を表す)
    • minVal >= maxx[i-1] が成り立つ場合、ans := i とする
  7. ans を返す

実装例

以下に C++ による実装を示します。

#include <bits/stdc++.h>
using namespace std;
class Solution {
   public:
   int partitionDisjoint(vector <int>& A) {
      int n = A.size();
      vector <int> maxx(n);
      int minVal = A[n - 1];
      maxx[0] = A[0];
      for(int i = 1; i < n; i++){
         maxx[i] = max(A[i], maxx[i - 1]);
      }
      int ans = A.size() - 1;
      for(int i = n - 1; i >= 1; i--){
         minVal = min(minVal, A[i]);
         if(minVal >= maxx[i - 1]){
            ans = i;
         }
      }
      return ans;
   }
};
main(){
   vector<int> v1 = {5,0,3,8,6};
   Solution ob;
   cout << (ob.partitionDisjoint(v1));
}

入力

[5,0,3,8,6]

出力

3

計算量

このアルゴリズムの時間計算量は O(n)、空間計算量も O(n) です。配列を前方向と後ろ方向にそれぞれ 1 回ずつ走査するだけで済むため、大規模な入力に対しても効率的に動作します。

  1. 【C++入門】配列を関数に渡す3つの方法をわかりやすく解説

    C++では、配列全体をそのまま関数の引数として渡すことはできません。しかし、インデックスを付けずに配列名を指定することで、配列へのポインタを渡すことができます。これは「配列名は先頭要素へのポインタに読み替えられる(配列の減衰)」というC++の仕組みによるものです。1次元配列を関数の引数として渡したい場合は、以下の3つのいずれかの方法で関数の仮引数を宣言します。どの方法でも、コンパイラに対して「整数型のポインタを受け取る」という情報が伝わるため、動作結果はすべて同じになります。配列を関数に渡す3つの宣言方法1. ポインタとして仮引数を宣言するvoid myFunction(int *param)

  2. Pythonで配列を互いに素な左右の部分配列に分割する方法を解説

    問題の概要 配列 nums が与えられたとき、これを「left」と「right」という2つの部分配列に分割します。この分割は、以下の条件を満たす必要があります。 left 内のすべての要素が、right 内のどの要素以下であること left と right がどちらも空でないこと left のサイズが可能な限り小さいこと そして、このような分割を行った後の left の長さを求めます。 具体例 たとえば、入力が nums = [5,0,3,8,6] の場合、出力は 3 になります。これは、left 配列が [5,0,3]、right 部分配列が [8,6] に分割されるためです。 解法のア