Pythonで最大k回の置換により同じ数が並ぶ最長の部分リストの長さを求める方法
問題概要
リスト nums と整数 k が与えられたとします。ここで「1回の操作」とは、リスト内の任意の要素の値を別の値に書き換えることを指します。最大 k 回までの操作を行った後、同じ数が繰り返し並んでいる 最長の部分リスト(連続する区間)の長さを求めるのが目的です。
入力例
たとえば、nums = [8, 6, 6, 4, 3, 6, 6]、k = 2 が入力された場合、出力は 6 になります。
理由は次のとおりです。値 4 と 3 を 6 に書き換えることで、配列は [8, 6, 6, 6, 6, 6, 6] となり、すべてが 6 で構成される部分リストの長さは 6 になります。
解法のアプローチ:スライディングウィンドウ
この問題はスライディングウィンドウ(尺取り法)を使うことで、線形時間 O(n) で効率的に解けます。ウィンドウ内で最も多く出現している数の出現回数を max_count として管理し、「ウィンドウ幅 − max_count > k」となったタイミングでウィンドウの左端を縮めていくのがポイントです。
具体的な手順
numsが空の場合は0を返します。num_count:各数値の出現回数を記録するマップ(defaultdict)を用意します。max_count := 0:ウィンドウ内の最多出現回数を初期化します。start := 0:ウィンドウの左端インデックスです。- 各インデックス
endとその値numに対して以下を繰り返します。num_count[num]を 1 増やします。max_countを必要に応じて更新します。end - start + 1 > max_count + kの場合、左端の要素のカウントを 1 減らし、startを 1 進めます。
- 最後に
end - start + 1を返します。
この方法では、ウィンドウは一度も縮小して「答えより短くなる」ことがないため、常にこれまでの最良の長さ以上が保持され、正しい結果が得られます。
Pythonでの実装例
from collections import defaultdict
def solve(nums, k):
if not nums:
return 0
num_count = defaultdict(int)
max_count = 0
start = 0
for end, num in enumerate(nums):
num_count[num] += 1
max_count = max(max_count, num_count[num])
if end - start + 1 > max_count + k:
num_count[nums[start]] -= 1
start += 1
return end - start + 1
nums = [8, 6, 6, 4, 3, 6, 6]
k = 2
print(solve(nums, k))
入力
[8, 6, 6, 4, 3, 6, 6], 2
出力
6
計算量
リストを一度だけ走査するため、時間計算量は O(n)、出現回数を記録するマップが必要とする空間計算量も O(n) となります(n はリストの長さ)。素朴な全探索(O(n²) 以上)に比べて大幅に高速であり、大きな入力にも対応できます。
-
【Python】ノードを重複させずにDAGの最長パスの長さを求めるプログラム
DAGの最長パス問題とは 隣接リスト形式で表された有向非巡回グラフ(DAG: Directed Acyclic Graph)が与えられたとき、同じノードを2度通らずに辿れる最長パスの長さを求める問題を考えます。 例として、次のようなグラフを想定してみましょう。 この場合、パス「0 → 1 → 3 → 4 → 2」が最長となるため、出力は 4 になります。 解法のアプローチ:DFSとメモ化の組み合わせ この問題は、深さ優先探索(DFS)にメモ化(結果のキャッシュ)を組み合わせることで効率的に解けます。各ノードから始まる最長パスの長さを一度計算したら結果を保存し、同じ計算を繰り返さないのがポイ
-
Pythonで1つの要素を削除して作れる最長の連続増加サブリストの長さを求める方法
問題の概要 数値のリスト nums が与えられます。ここで、リストから0個または1個の要素を削除できるものとし、その結果として得られる「連続した厳密に増加する部分リスト(サブリスト)」の最大の長さを求めます。 たとえば、入力が nums = [30, 11, 12, 13, 14, 15, 18, 17, 32] の場合、答えは 7 になります。18 を削除すれば [11, 12, 13, 14, 15, 17, 32] という最も長い連続した厳密増加部分リストが得られ、その長さがちょうど 7 になるためです。 解法の考え方 この問題は、次の2つの配列を用意すると効率よく解けます。 pre