問題
英小文字の文字列 S があります。 空文字 T に対して次の操作を繰り返すことで、S=T である状態にできるかどうかを判定してください。 「T の末尾に"dream"、"dreamer"、"erase"、"eraser"のいずれかを追加する」
解法・ソースコード
まず 再帰関数 を用いた 全探索解法 を考えます。
次のように 再帰関数 を定義します。
rec(i) ← 文字列Sの最初のi文字分が、"dream"、"dreamer"、"erase"、"eraser"の連結で作れるかどうかを表すブール値(True/False)
文字列Sの長さをNとしたとき、rec(n)が最終的な答えとなります。
rec(i)を求めるために、次の4パターンに分けて考えます。
- s[0:i]の末尾を”erase”で区切る場合
rec(i - 5)がTrue かつ s[0:1]の最後の5文字が”erase”であるならば、rec(i)はTrue - s[0:i]の末尾を”eraser”で区切る場合
rec(i - 6)がTrue かつ s[0:1]の最後の5文字が”eraser”であるならば、rec(i)はTrue - s[0:i]の末尾を”dream”で区切る場合
rec(i - 5)がTrue かつ s[0:1]の最後の5文字が”dream”であるならば、rec(i)はTrue - s[0:i]の末尾を”dreamer”で区切る場合
rec(i - 7)がTrue かつ s[0:1]の最後の5文字が”dreamer”であるならば、rec(i)はTrue
この 再帰関数 rec(i) を踏まえて、動的計画法 を表す 配列memo を次のように定義します。
memo[i] ← s[0:i]が、"dream"、"dreamer"、"erase"、"eraser"の連結で作れるどうかを表すブール値(True/False)
memo[0]、memo[1]、…、memo[n] の値を順番に求めていきます。
[Google Colaboratory]
1 | #---------- 入力例 ---------- |
[実行結果]
5 erase 10 dream memo [True, False, False, False, False, True, False, False, False, False, True] 解:Yes
“erase” + “dream” で、“erasedream” という文字列が作成できるので、正解は “Yes”(作成できる) となります。