Pythonでリストを合計が等しい2つのグループに分割できるか判定する方法
数値のリスト nums が与えられたとき、その要素を2つのグループに分割し、それぞれのグループに含まれる要素の合計が等しくなるようにできるかどうかを判定することを考えます。
例えば、入力が nums = [2, 3, 6, 5] の場合、[2, 6] と [3, 5] という2つのグループに分けることができるため、出力は True になります。
解決のアプローチ
この問題は、動的計画法(DP)を用いた「部分和問題」として解くことができます。ポイントは、まず全体の合計を求め、それが偶数であれば「合計の半分に等しい部分和が作れるか」を確認するだけだという点です。具体的には以下の手順で進めます。
total:= nums の全要素の合計を求めるtotalが奇数の場合はFalseを返す(2つのグループで同じ合計にできないため)half:= total ÷ 2 の整数部分dp:= サイズ half + 1 のリストを用意し、すべてFalseで初期化するdp[0] := Trueとする(合計0は常に達成可能なため)nums の各要素 num に対して、i を half から 0 へ降順にループし、i ≥ num であれば
dp[i] = dp[i] OR dp[i - num]と更新する最後に
dp[half]を返す
内側のループを降順に処理するのは重要なテクニックです。昇順に処理すると同じ要素を何度も使ってしまう可能性がありますが、降順にすることで各要素を一度しか使わないことを保証できます。
実装例
class Solution: def solve(self, nums): total = sum(nums) if total & 1: return False half = total // 2 dp = [True] + [False] * half for num in nums: for i in range(half, 0, -1): if i >= num: dp[i] |= dp[i - num] return dp[half] ob = Solution() nums = [2, 3, 6, 5] print(ob.solve(nums))
入力
[2, 3, 6, 5]
出力
True
このように、DPテーブルを活用することで、リストを合計の等しい2つのグループに分割できるかどうかを効率的に判定できます。計算量は O(n × half) となり、要素数や合計値がそれほど大きくない場合に実用的な手法です。
-
Pythonで左右の部分木の入れ替えにより2つの二分木を一致させられるか判定する方法
問題の概要 2つの二分木が与えられたとき、任意のノードについて左部分木と右部分木を何度でも入れ替えてよいと仮定します。この操作を繰り返すことで、1つ目の木を2つ目の木とまったく同じ形に変換できるかどうかを判定するのが、この記事で扱う問題です。 例えば、次のような2つの木が入力として与えられた場合、左右の入れ替えによって一致させられるため、出力は True になります。 解決のアプローチ この問題は、幅優先探索(BFS)の考え方を使い、木をレベル(深さ)ごとに処理しながらノードの値を比較することで解けます。左右の入れ替えによって同じレベル内の値の並び順は反転し得るため、「順方向」または「逆方
-
Pythonで合計がkに等しい4つの異なる要素を見つけられるか判定するプログラム
問題の概要 数値のリスト nums と値 k が与えられたとき、リスト内に合計が k と等しくなる4つの異なる要素が存在するかどうかを判定します。 たとえば、入力が nums = [11, 4, 6, 10, 5, 1]、k = 25 の場合、[4, 6, 10, 5] の合計が25になるため、出力は True となります。 解法のアプローチ:ソート + 双方向ポインタ法 この問題は、いわゆる「4Sum」問題と呼ばれるものです。全組み合わせを総当たりすると計算量が膨大になりますが、リストをソートしたうえで双方向ポインタ(two pointers)テクニックを使うことで、効率よく探索できます。