C++でリストを左右に分割できるか判定するアルゴリズム
問題の概要
整数のリスト nums が与えられたとき、このリストを2つの空でない部分リストに分割できるかどうかを判定します。ただし、左側の部分リストに含まれるすべての数値は、右側の部分リストに含まれるすべての数値よりも厳密に小さい必要があります。
例えば、入力が [6, 4, 3, 8, 10] の場合を見てみましょう。left = [6, 4, 3]、right = [8, 10] と分割すると、左側の最大値 6 は右側の最小値 8 より小さいため、出力は true(1)になります。
解決のアプローチ
この問題は、プレフィックス最大値(左側からの累積最大値)とサフィックス最小値(右側からの累積最小値)を事前に計算しておくことで、効率的に解くことができます。
具体的な手順は以下の通りです。
nをnumsのサイズとするサイズ
nの配列leftとrightを定義するleft[0] = nums[0]、rightの末尾要素 =numsの末尾要素 として初期化するi = 1からn - 1までループ:left[i] = max(left[i - 1], nums[i])(インデックス i までの左側の最大値を記録)i = n - 2から0まで逆順にループ:right[i] = min(right[i + 1], nums[i])(インデックス i 以降の右側の最小値を記録)i = 0からn - 2までループ:left[i] < right[i + 1]を満たす位置があればtrueを返すどの分割位置でも条件を満たさなければ
falseを返す
計算量
- 時間計算量: O(n) — 各配列をそれぞれ一度ずつ走査するだけです
- 空間計算量: O(n) — 補助配列
leftとrightが必要です
C++ 実装例
それでは、理解を深めるために以下の実装例を見てみましょう。
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
bool solve(vector<int> &nums) {
int n = nums.size();
vector<int> right(n);
vector<int> left(n);
left[0] = nums[0];
right.back() = nums.back();
for (int i = 1; i < n; i++) {
left[i] = max(left[i - 1], nums[i]);
}
for (int i = n - 2; i >= 0; i--) {
right[i] = min(right[i + 1], nums[i]);
}
for (int i = 0; i < n - 1; i++) {
if (left[i] < right[i + 1])
return true;
}
return false;
}
};
main() {
Solution ob;
vector<int> v = {6,4,3,8,10};
cout << (ob.solve(v));
}入力
{6,4,3,8,10}出力
1
まとめ
この手法では、各分割位置における「左側の最大値」と「右側の最小値」を前処理で求めておくことで、全ての分割候補を線形時間でチェックできます。ナイーブな全探索では O(n²) かかるところを、O(n) まで高速化できるのがポイントです。
-
C++でリンクリストをフラット化する方法【ソート済みリストの統合】
この問題では、right と down という2つのポインタを持つノードで構成されるリンクリストが与えられます。 rightポインタ: メインとなるリンクリストをつなぐためのポインタです。 downポインタ: そのノードから始まるサブリンクリストをつなぐためのポインタです。 すべてのリンクリストはそれぞれソート済みであるものとします。求められているのは、これらの複数のリンクリストを1本のリストにまとめる(フラット化する)プログラムを作成することです。そして、結果として得られるリストもソート済みの状態になっていなければなりません。 問題の例 入力: 出力: 1-> 9->
-
Pythonでリストを任意の位置で分割してサブリストを作成する方法
データ分析の現場では、データを整形したり移動させたりといった複雑な処理が求められる場面が多くあります。そのような状況で役立つのが、1つの大きなリストを要件に応じて複数のサブリストに分割するテクニックです。本記事では、Pythonでリストを指定した位置で分割するための代表的なアプローチを、具体的なコード例とともに解説します。方法1:zipとforループ(リスト内包表記)を使うこのアプローチでは、まずスライス(リストダイス)を使って分割開始位置から要素を取り出します。次に、zip関数とforループ(リスト内包表記)を組み合わせることで、分割ポイントごとにサブリストを生成します。[0] + spli