Pythonで「良い部分配列」の最大スコアを求めるアルゴリズムと実装
問題の概要
整数配列 nums とインデックス k が与えられます。部分配列 (i, j) のスコアは、次のように定義されます。
score(i, j) = min(nums[i..j]) × (j − i + 1)
つまり「部分配列内の最小値 × 部分配列の長さ」です。ここで、i ≤ k ≤ j を満たす部分配列を「良い部分配列(good subarray)」と呼びます。この記事の目的は、良い部分配列の中から最大のスコアを見つけることです。
入力例
nums = [2,5,4,8,5,6]、k = 3 の場合を考えてみましょう。最適な部分配列は (1, 5) で、nums[1..5] の最小値は 4 です。したがって、スコアは 4 × (5 − 1 + 1) = 20 となります。
解法の考え方
この問題は、インデックス k を中心に領域を左右へ拡張していく貪欲法を使えば、O(n) の計算量で効率的に解けます。基本的なアイデアは次のとおりです。
- まず k の位置だけを範囲とし、そこから左右のポインタ i と j を広げていきます。
- 現在の最小値 minNum 以上の要素は、スコアを下げることなく範囲に取り込めます。そこで、minNum 未満の要素に行き当たるまでポインタを進めます。
- 各段階で「現在の幅 × 現在の最小値」を計算し、答えを更新します。
- その後、両端のうち大きい方の値を新しい最小値の候補として採用し、再度拡張を行います。これにより、あり得るすべての「最小値の水準」を漏れなく評価できます。
アルゴリズムの手順
- ans と minNum を nums[k] で初期化する。
- ポインタ i と j をどちらも k に設定する。
- i > -1 または j < 配列のサイズ である間、次を繰り返す。
- nums[i] ≥ minNum である限り、i を左へ移動する。
- nums[j] ≥ minNum である限り、j を右へ移動する。
- ans を max(ans, (j − i − 1) × minNum) で更新する。
- minNum を、範囲外の場合は -1 として、nums[i] と nums[j] の大きい方で更新する。
- ans を返す。
Pythonでの実装例
理解を深めるために、以下の実装を見てみましょう。
def solve(nums, k):
ans = nums[k]
minNum = nums[k]
i = k
j = k
while i > -1 or j < len(nums):
while i > -1 and nums[i] >= minNum:
i -= 1
while j < len(nums) and nums[j] >= minNum:
j += 1
ans = max(ans, (j - i - 1) * minNum)
minNum = max(nums[i] if i > -1 else -1,
nums[j] if j < len(nums) else -1)
return ans
nums = [2,5,4,8,5,6]
k = 3
print(solve(nums, k))
実行結果
入力:
[2,5,4,8,5,6], 3
出力:
20
計算量
- 時間計算量: O(n)。左右のポインタはそれぞれ配列を一度だけ走査するため、全体で線形時間で処理できます。
- 空間計算量: O(1)。追加のデータ構造は一切不要です。
まとめ
「最小値 × 長さ」で定義されるスコアの最大化問題は、単調な拡張戦略(貪欲法)によって効率的に解けます。k を必ず含むという制約があるため、k を起点に左右へ領域を広げるこの手法が自然な選択になります。同様のパターンは LeetCode の「Maximum Score of a Good Subarray」などの問題にも応用できるので、ぜひマスターしておきましょう。
-
Pythonで部分配列の合計をmで割った余りの最大値を求めるプログラム
問題の概要 n個の要素からなる配列 nums と整数 m が与えられたとき、任意の部分配列(連続する要素の集合)の合計を m で割った余りの最大値を求めることを考えます。 たとえば、nums = [1,5,7,3]、m = 5 が入力として与えられた場合、出力は 3 になります。すべての部分配列について余りを計算すると、次のようになります。 [1] mod 5 = 1 [5] mod 5 = 0 [7] mod 5 = 2 [3] mod 5 = 3 [1,5] mod 5 = 1 [5,7] mod 5 = 2 [7,3] mod 5 = 0 [1,5,7] mod 5 = 3 [5,7,
-
Pythonで制約付きの建物の最大高さを求めるプログラム
問題の概要整数 n と制約リスト restrictions が与えられたとします。私たちは都市に n 棟の新しい建物を一列に建てようとしていますが、高さに関するいくつかの制限があります。建物には左から順に 1 から n までの番号が付けられており、各制約は restrictions[i] = (id_i, max_height_i) の形式で表され、「id_i 番の建物の高さは max_height_i 以下でなければならない」ことを意味します。建物の高さに関する都市の規則は以下のとおりです。各建物の高さは 0 以上でなければなりません。1 番の建物(最初の建物)の高さは必ず 0 です。隣接す