私は、CormemのIntroduction to Algorithms 3rd edition(pg 405)から動的計画問題を解決しようとしています。
回文は、同じ前方と後方を読み取るいくつかのアルファベット上の空でない文字列です。回文の例は、すべて長さ1
civic
、、、、racecar
およびaibohphobia
(回文の恐怖)の文字列です。与えられた入力文字列のサブシーケンスである最長の回文を見つけるための効率的なアルゴリズムを提供します。たとえば、入力が与えられた場合
character
、アルゴリズムはを返す必要がありますcarac
。
ええと、私はそれを2つの方法で解決することができました:
最初の解決策:
文字列の最長パリンドロームサブシーケンス(LPS)は、それ自体の最長共通サブシーケンスとその逆です。(シーケンスの最長増加部分列を求める別の関連する質問を解決した後、このソリューションを構築しました)。これは単なるLCSバリアントであるため、O(n²)時間とO(n²)メモリも必要です。
2番目の解決策:
2番目の解決策はもう少し複雑ですが、一般的なLCSテンプレートにも準拠しています。それは次の再発から来ています:
lps(s[i..j]) =
s[i] + lps(s[i+1]..[j-1]) + s[j], if s[i] == s[j];
max(lps(s[i+1..j]), lps(s[i..j-1])) otherwise
lpsの長さを計算するための擬似コードは次のとおりです。
compute-lps(s, n):
// palindromes with length 1
for i = 1 to n:
c[i, i] = 1
// palindromes with length up to 2
for i = 1 to n-1:
c[i, i+1] = (s[i] == s[i+1]) ? 2 : 1
// palindromes with length up to j+1
for j = 2 to n-1:
for i = 1 to n-i:
if s[i] == s[i+j]:
c[i, i+j] = 2 + c[i+1, i+j-1]
else:
c[i, i+j] = max( c[i+1, i+j] , c[i, i+j-1] )
lpを効果的に構築したい場合は、それでもO(n²)の時間とメモリが必要です(テーブル上のすべてのセルが必要になるため)。LCSのようなメモリの少ないアプローチ(LISはO(n)メモリで解決可能)以外のアプローチで解決できるLISなどの関連する問題を分析して、O(n)メモリで解決できるかどうか疑問に思いました。それも。
LISは、候補のサブシーケンスをリンクすることでこの限界を達成しますが、パリンドロームでは、ここで重要なのはサブシーケンスの前の要素ではなく、最初の要素であるため、より困難です。誰かがそれを行うことが可能かどうか知っていますか、または以前のソリューションはメモリが最適ですか?