【Python】1つの要素を削除して作れる最長の連続増加部分リストの長さを求めるアルゴリズム
問題概要
数値のリスト nums が与えられたとき、最大で1つの要素を削除できるという条件のもとで、連続した「厳密に増加する」部分リスト(サブリスト)の最大の長さを求めます。ここで「厳密に増加する」とは、隣り合う要素が必ず前より大きくなっている状態を指します。
例えば、入力が nums = [35, 5, 6, 7, 8, 9, 12, 11, 26] の場合、答えは 7 になります。これは、リストから 12 を削除すると [5, 6, 7, 8, 9, 11, 26] となり、この部分リストの長さが7で、これ以上長い連続増加部分リストは存在しないためです。
解法のアプローチ:両方向からのDP
この問題は、動的計画法(DP)の考え方を使うことで効率的に解けます。ポイントは、各位置について「そこで終わる増加列の長さ」と「そこから始まる増加列の長さ」をそれぞれ事前に計算しておくことです。
アルゴリズムの手順
numsが空の場合は0を返します。end:numsと同じサイズのリストを作り、すべて1で初期化します。end[i]は「インデックス i で終わる連続増加列の長さ」を表します。start: 同じく同じサイズのリストを1で初期化します。start[j]は「インデックス j から始まる連続増加列の長さ」を表します。- i を 1 から
len(nums) - 1まで順に処理し、nums[i] > nums[i - 1]であればend[i] = end[i - 1] + 1と更新します。 - j を
len(nums) - 2から 0 まで逆順に処理し、nums[j + 1] > nums[j]であればstart[j] = start[j + 1] + 1と更新します。 resをendとstartの全要素の最大値として初期化します(何も削除しないケース)。- k を 1 から
len(nums) - 2まで順に処理し、「k 番目の要素を削除する」ケースを検討します。nums[k - 1] < nums[k + 1]が成り立てば、削除によって両側の増加列をつなげられるので、resをmax(res, end[k - 1] + start[k + 1])で更新します。 - 最後に
resを返します。
実装例
以下が実際のPythonコードです。
def solve(nums):
if not nums:
return 0
end = [1 for i in nums]
start = [1 for i in nums]
# 左から右へ:各位置で終わる増加列の長さ
for i in range(1, len(nums)):
if nums[i] > nums[i - 1]:
end[i] = end[i - 1] + 1
# 右から左へ:各位置から始まる増加列の長さ
for j in range(len(nums) - 2, -1, -1):
if nums[j + 1] > nums[j]:
start[j] = start[j + 1] + 1
# 要素を削除しない場合の最大値
res = max(max(end), max(start))
# 1つの要素を削除して増加列をつなげる場合
for k in range(1, len(nums) - 1):
if nums[k - 1] < nums[k + 1]:
res = max(res, end[k - 1] + start[k + 1])
return res
nums = [35, 5, 6, 7, 8, 9, 12, 11, 26]
print(solve(nums))
入力
[35, 5, 6, 7, 8, 9, 12, 11, 26]
出力
7
計算量について
このアルゴリズムは、リストを前方向・後ろ方向・中間チェックの合計3回走査するだけなので、時間計算量は O(n)、補助配列2つ分の領域が必要なため空間計算量も O(n) となります。全ての削除候補を毎回試す総当たり方式(O(n²))よりも大幅に効率的です。
-
Pythonで最長連続シーケンスの長さを求めるアルゴリズムと実装方法
問題概要ソートされていない数値の配列が与えられたとき、その中から連続する要素で構成される最長シーケンスの長さを見つける問題を考えてみましょう。ここでいう「連続」とは、値が1ずつ増えていく数列(例:4, 5, 6, 7)のことを指します。例えば、入力が nums = [70, 7, 50, 4, 6, 5] の場合、最も長い連続シーケンスは [4, 5, 6, 7] となるため、答えは 4 になります。解法のアプローチこの問題は、以下の手順で効率的に解くことができます。まず、配列をセット(set)に変換して重複を除去します。これにより、要素の存在確認が O(1) で行えるようになります。各要素
-
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