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

Pythonで3つ以上の文字列から最長の共通部分文字列を見つける方法【動的計画法】


最長共通部分文字列(Longest Common Substring)を求めるアルゴリズムは、動的計画法(DP)を用いることで効率的に解けます。一般的なDP実装では、O(nm)の時間計算量で処理が可能です(n、mは比較対象となる文字列の長さ)。以下に、最長共通部分文字列アルゴリズムの実装例を示します。

実装例

def longest_common_substring(s1, s2):
    m = [[0] * (1 + len(s2)) for i in range(1 + len(s1))]
    longest, x_longest = 0, 0
    for x in range(1, 1 + len(s1)):
        for y in range(1, 1 + len(s2)):
            if s1[x - 1] == s2[y - 1]:
                m[x][y] = m[x - 1][y - 1] + 1
                if m[x][y] > longest:
                    longest = m[x][y]
                    x_longest = x
            else:
                m[x][y] = 0
    return s1[x_longest - longest: x_longest]

print(longest_common_substring('wellbeing', 'welcome'))

このコードでは、「wellbeing」と「welcome」という2つの文字列を比較し、両方に共通して現れる最も長い部分文字列を抽出しています。

出力結果

wel

アルゴリズムの仕組み

このアルゴリズムは、以下の手順で動作します。

  • まず、カウンターとして機能する2次元配列(m)を、すべて0で初期化します。

  • 1行目から処理を開始し、文字列s1の各文字と、s2のすべての文字を順に比較していきます。

  • s2の文字を走査している途中で、s1側の文字と一致した場合にはカウンターを1つ増やします。この値は、左上の対角位置の値を引き継ぐ形で、m[i][j]に保存されます。

すべてのループが終わった時点で、ループ内で記録しておいたインデックス情報をもとに、最も長かった部分文字列を切り出して返します。

Python 3で利用する際の注意点

オリジナルのコードで使用されていたxrange()はPython 2専用の関数です。Python 3環境では、組み込みのrange()に置き換えるだけで同じように動作します。上記のコードは、すでにPython 3向けに書き直したものです。

3つ以上の文字列へ拡張する方法

3つ以上の文字列から共通部分文字列を求めたい場合は、標準ライブラリのfunctools.reduce()を活用して、2文字列用の関数を繰り返し適用するのが手軽です。

from functools import reduce

strings = ['wellbeing', 'welcome', 'welfare']
result = reduce(longest_common_substring, strings)
print(result)
wel

この方法では、最初の2つの文字列の共通部分文字列を求め、その結果と次の文字列との共通部分文字列を求める……という処理を文字列の数だけ繰り返します。ただし、ペアごとの逐次処理であるため、厳密な意味で「全文字列に共通する最長の部分文字列」を必ず保証するわけではない点には注意してください。より厳密な結果が必要な場合は、一般化接尾辞木(generalized suffix tree)などを採用した手法の検討も有効です。


  1. 【Python入門】2つの文字列から珍しい単語(ユニークな単語)を見つけるプログラムの作り方

    はじめに この記事では、以下の問題文に対する解決方法を、実際のコード例とともにわかりやすく解説します。 問題文 2つの文字列が与えられたとき、その中から「珍しい単語」(どちらか一方の文字列にしか出現しない単語)をすべて抽出することを目標とします。両方の文字列に共通して含まれる単語は除外します。 解決のアプローチ ここでは辞書(dict)を使った出現回数のカウント方式を採用します。手順は次のとおりです。 空の辞書を用意する 各文字列をsplit()で単語ごとに分割する 各単語の出現回数を辞書に記録する 出現回数がちょうど1回の単語だけを結果として返す 実装例 # 珍しい単語を見つける関

  2. Pythonで2つのソート済み配列から最も近いペアを見つける方法

    この記事では、昇順にソートされた2つの配列から「目標値に最も近い合計を持つペア」を見つける問題と、その効率的な解法について詳しく解説します。問題文問題: ソート済みの2つの配列と目標値 x が与えられます。各配列から1つずつ要素を選んで作るペアのうち、その合計が x に最も近くなる組み合わせを見つけてください。解き方のポイント:二ポインタ法すべてのペアを総当たりで調べると計算量は O(m×n) になりますが、配列がソート済みであることを活かせば、二ポインタ法によって O(m+n) まで高速化できます。手順は以下の通りです。片方の配列は先頭から、もう片方の配列は末尾から走査を開始します。現在のペ