Pythonで最大部分配列(Maximum Subarray)問題を解く方法【動的計画法】
最大部分配列問題とは
整数配列 A が与えられたとき、長さが 1 以上の連続する部分配列の中で、要素の合計が最大になるものを見つけ、その合計値を返すことを考えます。
例えば、配列 A = [-2, 1, -3, 4, -1, 2, 1, -5, 4] の場合、最大の合計は 6 となり、これは部分配列 [4, -1, 2, 1] の合計に相当します。
解き方:動的計画法(DP)
この問題は、動的計画法(Dynamic Programming)を使うことで効率的に解くことができます。手順は以下の通りです。
- 配列 A と同じサイズの配列 dp を定義し、0 で初期化する
- dp[0] := A[0] とする
- i = 1 から A のサイズ − 1 まで繰り返す
- dp[i] := max(dp[i−1] + A[i], A[i]) とする
- dp 内の最大値を返す
ここでのポイントは、「i 番目の要素で終わる部分配列の最大合計」を dp[i] として記録していく点です。直前までの累積合計がマイナスになる場合は、そこから新しく部分配列を始めた方が得であるため、max() を使って「継続するか、新しく始めるか」を判断しています。
それでは、実際の実装例を見てみましょう。
Pythonでの実装例
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
dp = [0 for i in range(len(nums))]
dp[0] = nums[0]
for i in range(1, len(nums)):
dp[i] = max(dp[i-1] + nums[i], nums[i])
# print(dp)
return max(dp)
nums = [-2, 1, -3, 7, -2, 2, 1, -5, 4]
ob1 = Solution()
print(ob1.maxSubArray(nums))
入力
nums = [-2, 1, -3, 7, -2, 2, 1, -5, 4]
出力
8
この入力の場合、最大となる部分配列は [7, -2, 2, 1] であり、その合計は 8 になります。
計算量について
このアルゴリズムは配列を一度だけ走査するため、時間計算量は O(n) です。また、dp 配列を使用するため空間計算量は O(n) となりますが、dp 配列を使わずに「現在の累積合計」と「これまでの最大値」の 2 つの変数だけを保持すれば、空間計算量を O(1) に抑えることも可能です(この手法は一般に「カダネのアルゴリズム」と呼ばれています)。
-
Pythonで最短の「ソートされていない連続部分配列」を見つける方法
整数配列が与えられたとき、「その部分配列だけを昇順にソートすれば、配列全体がソート済みの状態になる」という条件を満たす連続する部分配列の中で、最も短いものを求めてその長さを出力することを考えます。 例えば、配列が [2,6,4,8,10,9,15] の場合、答えは 5 になります。これは、[6,4,8,10,9] の部分だけを昇順に並べ替えると、配列全体が [2,4,6,8,9,10,15] と完全にソートされた状態になるためです。 解法のアプローチ この問題は、次の手順で解くことができます。 元の配列 nums を昇順にソートしたコピー res を作成します。 各インデックス i について
-
【Python入門】3つの数値から最大値を求める方法
3つの数値 a、b、c が与えられたとき、その中で最も大きい要素(最大値)を見つけるのが今回の課題です。ここでは、Pythonのリストと組み込み関数 max() を使ったシンプルな方法を、初心者向けにわかりやすく解説します。 実行例 入力:a = 2, b = 4, c = 3 出力:4 アルゴリズム ステップ1:ユーザーから3つの数値を入力として受け取る。 ステップ2:3つの数値をリストに格納する。 ステップ3:max() 関数を使ってリスト内の最大値 max(lst) を求める。 ステップ4:最後に最大値を出力する。 サンプルコード def maximum(a, b, c):