Pythonで2つの文字列の共通プレフィックス(接頭辞)を抽出して圧縮するプログラム
問題の概要
2つの文字列 s と t(いずれも小文字の英字で構成)が与えられたとします。このとき、3つのペアからなるリストを作成します。各ペアは (l, k) の形式で表され、k は文字列、l はその長さです。
3つのペアの中身は次のとおりです。
- 1つ目:s と t の最長共通プレフィックス(共通接頭辞)p
- 2つ目:p を取り除いた後の s の残りの部分 s'
- 3つ目:p を取り除いた後の t の残りの部分 t'
最終的な出力は、[(pの長さ, p), (s'の長さ, s'), (t'の長さ, t')] という形式になります。
たとえば、入力が s = "science"、t = "school" の場合、先頭の "sc" が共通しているため、出力は次のようになります。
[(2, 'sc'), (5, 'ience'), (4, 'hool')]
解決の手順
この問題は、次の手順で解くことができます。
- 空文字列 lcp を用意する
- i を 0 から min(len(s), len(t)) - 1 まで繰り返す
- s[i] と t[i] が一致していれば、lcp に s[i] を追加する
- 不一致になった時点で break すると、より安全に共通プレフィックスを求められる
- s_rem := s の len(lcp) 番目以降の部分文字列
- t_rem := t の len(lcp) 番目以降の部分文字列
- [(len(lcp), lcp), (len(s_rem), s_rem), (len(t_rem), t_rem)] を返す
実装例
以下にPythonでの実装例を示します。なお、元のアルゴリズムでは不一致が起きてもループが継続するため、途中で異なる文字が現れた後に再び一致した場合に誤った結果になる可能性があります。ここでは break を加えて、より堅牢な形にしています。
def solve(s, t):
lcp = ''
for i in range(min(len(s), len(t))):
if s[i] == t[i]:
lcp += s[i]
else:
break # 不一致の時点で共通プレフィックスは終了
s_rem = s[len(lcp):]
t_rem = t[len(lcp):]
return [(len(lcp), lcp), (len(s_rem), s_rem), (len(t_rem), t_rem)]
s = "science"
t = "school"
print(solve(s, t))入力
"science", "school"
出力
[(2, 'sc'), (5, 'ience'), (4, 'hool')]
計算量について
このアルゴリズムは、短い方の文字列の長さを n としたとき、時間計算量 O(n)、空間計算量 O(n) で動作します。文字列スライスによって残りの部分を簡単に取得できるため、非常にシンプルかつ効率的な実装となっています。
-
【Python入門】2つの文字列から珍しい単語(ユニークな単語)を見つけるプログラムの作り方
はじめに この記事では、以下の問題文に対する解決方法を、実際のコード例とともにわかりやすく解説します。 問題文 2つの文字列が与えられたとき、その中から「珍しい単語」(どちらか一方の文字列にしか出現しない単語)をすべて抽出することを目標とします。両方の文字列に共通して含まれる単語は除外します。 解決のアプローチ ここでは辞書(dict)を使った出現回数のカウント方式を採用します。手順は次のとおりです。 空の辞書を用意する 各文字列をsplit()で単語ごとに分割する 各単語の出現回数を辞書に記録する 出現回数がちょうど1回の単語だけを結果として返す 実装例 # 珍しい単語を見つける関
-
2つの行列を乗算するPythonプログラム
ユーザーが入力した2つの行列を受け取り、その積(乗算結果)を表示するのがこのプログラムの目的です。ここでは、ネストされたリスト(2次元リスト)を使って行列を表現します。 行列の乗算では、「1つ目の行列の行の要素」と「2つ目の行列の列の要素」をそれぞれ掛け合わせ、その合計値を結果行列の要素とします。つまり、結果行列の i 行 j 列の値は、行列Aの i 行目と行列Bの j 列目の対応する要素同士の積の総和になります。 アルゴリズム ステップ1:2つの行列を入力する。 ステップ2:ネストされたforループで、各行・各列を順番に走査する。 ステップ3:すべての要素が0で初期化された結果用行列を用