Pythonで配列の部分集合の和として表せない最小の正整数を求めるアルゴリズム
昇順にソートされた正の数の配列が与えられたとき、その配列の任意の部分集合の要素の合計として表すことのできない、最小の正の値を見つける必要があります。この問題は O(n) の時間計算量で解くことが求められます。
例えば、入力が A = [1, 4, 8, 12, 13, 17] の場合、出力は 2 になります。これは、1 は単独の要素として表せますが、2 はどの部分集合の合計によっても作れないためです。
解法のアプローチ
この問題は、貪欲法(Greedy法)の考え方を使うことで線形時間で解けます。手順は以下の通りです。
n:= 配列 A のサイズanswer:= 1(初期値)- i を 0 から n-1 まで繰り返す:
A[i] <= answerの場合:answer := answer + A[i]- それ以外の場合:ループを抜ける
answerを返す
なぜこのアルゴリズムが機能するのか
このアルゴリズムの鍵となるのは、変数 answer が「1 から answer - 1 までのすべての値は、これまで処理した要素で表現できる」という不変条件を常に満たすように更新される点です。
次の要素 A[i] が answer 以下であれば、既存の表現可能な範囲 [1, answer - 1] の各値に A[i] を加えることで、[1, answer + A[i] - 1] の範囲全体を表現できるようになります。
逆に、A[i] が answer より大きい場合、配列は昇順ソートされているため、それ以降の要素でも answer を作ることはできません。したがって、その時点の answer が求める最小の正整数となります。
実装例
def get_smallest_element(A):
n = len(A)
answer = 1
for i in range(0, n):
if A[i] <= answer:
answer = answer + A[i]
else:
break
return answer
A = [1, 4, 8, 12, 13, 17]
print(get_smallest_element(A))入力
[1, 4, 8, 12, 13, 17]
出力
2
処理の流れを追ってみる
上記の例では、以下のように処理が進みます。
- 初期状態:
answer = 1 A[0] = 1はanswer(1)以下なので、answer = 1 + 1 = 2A[1] = 4はanswer(2)より大きいため、ループを抜ける- 結果として 2 を返す
計算量
配列を一度だけ走査するため、時間計算量は O(n)、追加のメモリ使用量は O(1) となり、非常に効率的なアルゴリズムです。
-
Pythonで配列の合計を求める方法を徹底解説
この記事では、Pythonを使って配列(リスト)の合計を求める方法について詳しく解説します。 問題文 問題: 配列が与えられたとき、その配列に含まれるすべての要素の合計を計算してください。 最も基本的なアプローチは、配列全体を走査し、各インデックスの要素を順番に加算していく方法です。ここでは、まず組み込み関数を活用したシンプルな実装例を見ていきましょう。 方法1:組み込み関数 sum() を使う Pythonには、イテラブルなオブジェクトの合計を一発で計算できる組み込み関数 sum() が用意されています。これを使えば、コードは非常に簡潔になります。 サンプルコード # 合計を求める関数 de
-
Pythonで配列(リスト)の合計を求める方法をわかりやすく解説
この記事では、配列(リスト)の合計値を求めるという問題に対して、Pythonでの解決策とアプローチをわかりやすく解説します。 問題の定義 配列が入力として与えられたとき、その配列に含まれるすべての要素の合計を計算することを目標とします。 例えば、[1, 2, 3, 4, 5] という配列が与えられた場合、出力は 15 になります。 アプローチ1:ループを使った素朴な方法(総当たり法) 最も基本的な方法は、リストを先頭から順に走査し、各要素を合計用の変数に加算していくやり方です。手順は以下の通りです。 合計を格納する変数を 0 で初期化します。 for ループでリストの各要素を取り出し、順番に