動的計画法で 2 つの文字列に共通する最長の部分列を求める

2 つの​文字列から、​順番を​変えずに​文字を​拾って​作れる​共通の​並びの​うち、​いちばん長い物の​長さを​求めます。​2 つの​文字列の​前から​何文字かずつを​表の​縦と​横に​取り、​欄を​順に​埋める​動的計画の​練習です。

海外で定番の問題リスト 4 本のうち 2 本に入っています (Blind 75、NeetCode 150)

問題

文字列 a と b を受け取ります。どちらの文字列からも、文字をいくつか飛ばして (順番は変えずに) 拾い出せる文字列を「共通の部分列」と呼びます。共通の部分列のうち、いちばん長い物の長さを返す関数を書いてください。

  • 拾う文字は隣どうしでなくて構いません。ただし、元の文字列での順番は変えられません
  • 共通の部分列が 1 文字も無ければ 0 を返します
  • a と b の長さは、どちらも 0 以上 1000 以下です。空の文字列も来ます
  • 文字は英小文字だけです

入力と出力の例

例 1

s、t、r の 3 文字を、どちらからも順に拾えます。s、t、e も 3 文字ですが、4 文字の物はありません。

入力

a = "stream"
b = "master"

出力

3

例 2

b の全部の文字が、a の中に順に出てきます。

入力

a = "programming"
b = "gaming"

出力

6

例 3

同じ文字が 1 つもありません。

入力

a = "sky"
b = "dawn"

出力

0

面接での聞かれ方

面接では、2 つの文字列を比べる動的計画の入口として出されます。

  • 「2 つの文字列の、最長の共通部分列の長さを返してください」
  • 最初に「部分文字列 (続いた文字) ではなく部分列ですね?」と確かめられるかを見られます
  • 書き終えると「表を 2 行に減らせますか?」「長さではなく、部分列そのものを返せますか?」と続きます

「部分列」は飛び飛びでよく、「部分文字列」は続いていないといけません。言葉の違いを最初に確かめておきます。

アルゴリズムのチートシートの「動的計画法 (DP)」に、​この​型の​要点を​表と​コードで​まとめています。

main.py
def common_length(a, b):
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(common_length("stream", "master"))

できているか「例で確かめる」を押すと、問題の例を全部この関数に渡して、通ったかをここに出します