Pythonで長さxとyの重ならない2つのサブリストの最大合計を求める方法
問題概要
数値のリスト nums と整数 x、y が与えられたとき、それぞれ長さが x と y であり、互いに重なり合わない2つのサブリスト(部分リスト)を選び、その要素の合計の最大値を求めるのが今回の課題です。
たとえば、nums = [3, 2, 10, -2, 7, 6]、x = 3、y = 1 という入力の場合、出力は 22 になります。これは、長さ3のサブリストとして [3, 2, 10] を、もう一方として [7] を選んだ場合の合計(15 + 7 = 22)に該当します。
解法のアプローチ:累積和(Prefix Sum)を活用
この問題は、累積和を使うことで線形時間 O(n) で解くことができます。まず、リスト A の累積和を格納したリスト P を作成しておけば、任意の連続区間の合計を P[j] − P[i] という差分で即座に取得できるようになります。
具体的な手順は以下のとおりです。
- 累積和の構築: 要素0のみを含むリスト P を用意し、A の各要素 x に対して「P の末尾要素 + x」を追加していきます。
- solve 関数の定義: 引数として2つの長さ len1、len2 を受け取ります。「長さ len1 のサブリストが左側・長さ len2 のサブリストが右側」という配置を想定します。
- 各区間合計の算出: Q を「P[i + len1] − P[i]」(開始位置 i における長さ len1 の区間の合計)のリストとして生成します。
- プレフィックス最大値の作成: Q のコピーである prefix を作り、隣接要素同士を比較して「その位置までの最大値」に書き換えます。
- 答えの更新: ans を負の無限大で初期化し、右側サブリストの開始位置 i を len1 から len(P) − len2 まで動かしながら、「left(左側区間の合計の最大値)+ right(P[i + len2] − P[i])」との最大値で ans を更新します。
- メイン処理: solve(len1, len2) と solve(len2, len1) の大きい方を返します。これにより、「x のサブリストが左にある場合」と「y のサブリストが左にある場合」の両方をカバーできます。
実装コード
以下が実際の Python コードです。
class Solution:
def solve(self, A, len1, len2):
# 累積和の作成
P = [0]
for x in A:
P.append(P[-1] + x)
def solve(len1, len2):
# 長さ len1 の全区間の合計
Q = [P[i + len1] - P[i] for i in range(len(P) - len1)]
# プレフィックス最大値
prefix = Q[:]
for i in range(len(prefix) - 1):
prefix[i + 1] = max(prefix[i + 1], prefix[i])
ans = float("-inf")
# 右側サブリストの開始位置を走査
for i in range(len1, len(P) - len2):
left = prefix[i - len1]
right = P[i + len2] - P[i]
ans = max(ans, left + right)
return ans
return max(solve(len1, len2), solve(len2, len1))
ob = Solution()
nums = [3, 2, 10, -2, 7, 6]
x = 3
y = 1
print(ob.solve(nums, x, y))
入力
[3, 2, 10, -2, 7, 6], 3, 1
出力
22
計算量について
累積和の構築、プレフィックス最大値の作成、および本体のループはいずれもリスト長に比例して処理されるため、全体の時間計算量は O(n)、空間計算量も O(n) となります。すべての組み合わせを総当たりする O(n²) の素朴なアプローチと比べて大幅に高速で、大きな入力サイズでも安心して利用できます。
-
Pythonで二分木の隣接しないノードの最大合計を求めるアルゴリズム
問題の概要二分木が与えられたとき、親子関係にある2つのノードを同時に選ばないという制約のもとで、選択できるノードの値の合計の最大値を求める問題を考えてみましょう。例えば、次のような二分木が入力として与えられたとします。この場合、出力は 17 になります。これは、10、4、3 の3つのノードは互いに親子関係(隣接関係)にないため、すべて選択できるからです。解き方のアプローチこの問題は、各ノードについて「そのノードを選ぶ場合」と「選ばない場合」の2つの状態を再帰的に計算することで解けます。手順は以下の通りです。関数 f() を定義します。引数としてノードを受け取ります。ノードが null(存在しな
-
Pythonで数値が2の累乗かどうかを判定するプログラム
この記事では、以下の問題に対する解決策について詳しく解説します。 問題文 ある整数が与えられたとき、その数が2の累乗であるかどうかを判定する必要があります。 この問題は、主に次の2つのアプローチで解くことができます。 アプローチ1: 繰り返し2で割って判定する 数値を順に2で割っていき、途中で割り切れなくなった場合(奇数が出現した場合)は2の累乗ではありません。最終的に1に到達できれば、その数は2の累乗であると判定できます。なお、0は2の累乗に含まれないため、あらかじめ除外しています。この方法の時間計算量は O(log n) です。 サンプルコード # power of 2 def find(