Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで最長の回文部分列(パリンドローム)の長さを求めるプログラム

問題概要

小文字のみで構成された文字列 s が与えられます。この文字列から文字を順番を崩さずに選んで作れる、最長の回文部分列(パリンドロームサブシーケンス)の長さを求めましょう。

例えば、入力が s = "aolpeuvekyl" の場合、出力は 5 となります。これは、l・e・v・e・l を順に選ぶことで回文 "level" が構成できるためです。

解法のアプローチ

この問題は、区間を対象とした再帰的な動的計画法で解くことができます。区間 [i, j] における最長回文部分列の長さを dp(i, j) として定義し、以下の手順に従って計算します。

  • n := 文字列 s のサイズとする
  • 関数 dp() を定義する。引数は i と j
  • i と j が等しい場合は 1 を返す(1文字は必ず回文になる)
  • そうでなく i > j の場合は 0 を返す(空の区間のため)
  • それ以外の場合は次のように処理する
    • s[i] と s[j] が等しい場合:両端の文字を回文に使えるので、2 + dp(i + 1, j - 1) を返す
    • 等しくない場合:どちらか一方の端を除外して比較するため、max(dp(i + 1, j), dp(i, j - 1)) を返す
  • 最後に dp(0, n - 1) を返す

Pythonでの実装例

理解を深めるために、以下の実装を見てみましょう。

class Solution:
   def solve(self, s):
      n = len(s)
      def dp(i, j):
         if i == j:
            return 1
         elif i > j:
            return 0
         else:
            if s[i] == s[j]:
               return 2 + dp(i + 1, j - 1)
            else:
               return max(dp(i + 1, j), dp(i, j - 1))
      return dp(0, n - 1)
ob = Solution()
s = "aolpeuvekyl"
print(ob.solve(s))

入力

"aolpeuvekyl"

出力

5

計算量について

状態 (i, j) の組み合わせは最大で O(n²) 個存在します。各状態の計算は定数時間で行えるため、メモ化(キャッシュ)を追加すれば、全体の時間計算量は O(n²)、空間計算量も O(n²) に抑えられます。文字列が長くなる場合でも効率的に動作する実装となっています。

  1. Pythonで最長アナグラム部分列の長さを求めるプログラム

    問題の概要小文字のみで構成された2つの文字列 S と T が与えられたとき、「最も長いアナグラム部分列」の長さを求めます。ここでアナグラム部分列とは、両方の文字列に共通して含まれる文字を組み合わせて作れる、同じ文字構成を持つ部分列のことです。例えば、S = helloworld、T = hellorld の場合、答えは 8 になります。これは、両方の文字列で共有できる文字(h ×1、e ×1、l ×3、o ×1、r ×1、d ×1)の合計が8文字であるためです。解法のアプローチこの問題は、各文字列における文字の出現回数を数え、その最小値を合計することで効率的に解けます。手順は以下の通りです。文

  2. Pythonで最長のバランス括弧部分列の長さを求めるプログラム

    問題概要 文字列 s が与えられます。この文字列には括弧「(」と「)」が含まれており、その中からバランスの取れた(対応関係が成立している)括弧の部分列として最も長いものを見つけ、その長さを返すことが目標です。 たとえば、入力が s = ())(()( の場合、出力は 4 になります。「(」と「)」を選び抜いて ()() というバランスの取れた部分列を作れるためです。 解法のアプローチ この問題は、文字列を後ろから走査することで線形時間で解けます。閉じ括弧を先に確保しておき、開き括弧が出てきたときに対を成立させるという発想です。手順は以下の通りです。 結果を格納する変数 res を 0 で初