Pythonでテキスト内の2つの単語間の最小距離を求める方法
プログラミングの問題としてよく知られているのが、「テキスト中に現れる2つの指定単語の間の最小距離を求める」という課題です。
具体的には、文字列 word0、word1 および長いテキスト text が与えられたとき、テキスト内に出現する word0 と word1 の任意のペアについて、その間にある単語数として測られる距離の最小値を求めます。どちらか一方でもテキストに存在しない場合は -1 を返します。
問題の例
たとえば、次のような入力を考えてみましょう。
- text = "cat dog abcd dog cat cat abcd dog wxyz"
- word0 = "abcd"
- word1 = "wxyz"
この場合、出力は 1 になります。「abcd」と「wxyz」の間には「dog」という1つの単語しか存在しないためです。
解法のアプローチ
この問題は、テキストを単語ごとに分割し、両端から走査する「二ポインタ」的な手法で効率的に解けます。手順は以下のとおりです。
- テキストを空白で区切り、単語リスト word_list を作成する。
- 答え ans の初期値を、単語リストの長さ(最大値)とする。
- 左側のポインタ L を null(未設定)で初期化する。
- 右側のポインタ R を 0 から 単語リストの末尾まで順に動かし、以下を繰り返す。
- word_list[R] が word0 または word1 である場合:
- L が設定済みで、かつ word_list[R] が word_list[L] と異なる単語(つまり word0 と word1 のペア)なら、ans を「R − L − 1」と比較して小さい方に更新する。
- その後、L を R に更新する。
- word_list[R] が word0 または word1 である場合:
- 最後に、ans が初期値(リスト全体のサイズ)のままであれば -1 を返し、そうでなければ ans を返す。
このアルゴリズムの計算量は O(n)(n は単語数)であり、非常に効率的です。
実装例(Python)
それでは、実際のコードを見てみましょう。
class Solution:
def solve(self, text, word0, word1):
word_list = text.split()
ans = len(word_list)
L = None
for R in range(len(word_list)):
if word_list[R] == word0 or word_list[R] == word1:
if L is not None and word_list[R] != word_list[L]:
ans = min(ans, R - L - 1)
L = R
return -1 if ans == len(word_list) else ans
ob = Solution()
text = "cat dog abcd dog cat cat abcd dog wxyz"
word0 = "abcd"
word1 = "wxyz"
print(ob.solve(text, word0, word1))入力
"cat dog abcd dog cat cat abcd dog wxyz", "abcd", "wxyz"
出力
1
まとめ
この手法のポイントは、直前に対象単語が出現した位置だけを記憶しておくことです。これにより、全ペアを総当たりで調べる O(n²) のアプローチを避け、線形時間 O(n) で最小距離を求められます。テキスト処理や検索機能の実装など、実務でも応用範囲の広いテクニックなので、ぜひ理解しておきましょう。
-
Pythonで二分木の2つのノード間の距離を求めるプログラム
二分木が与えられたとき、その中の2つのノード間の距離を求めることを考えます。グラフの場合と同じように、2つのノードを結ぶ経路上の辺(エッジ)の数を数え、その本数を距離として返します。 二分木のノード構造 木の各ノードは、次のような構造を持っています。 data : <整数値> right : <木の別のノードへのポインタ> left : <木の別のノードへのポインタ> 問題の例 例として、次のような二分木を考えてみましょう。 この木において、ノード「2」とノード「8」の間の距離を求めたいとします。このときの出力は 4 になります。 ノード2からノード8へ至
-
【Python入門】2つの文字列から珍しい単語(ユニークな単語)を見つけるプログラムの作り方
はじめに この記事では、以下の問題文に対する解決方法を、実際のコード例とともにわかりやすく解説します。 問題文 2つの文字列が与えられたとき、その中から「珍しい単語」(どちらか一方の文字列にしか出現しない単語)をすべて抽出することを目標とします。両方の文字列に共通して含まれる単語は除外します。 解決のアプローチ ここでは辞書(dict)を使った出現回数のカウント方式を採用します。手順は次のとおりです。 空の辞書を用意する 各文字列をsplit()で単語ごとに分割する 各単語の出現回数を辞書に記録する 出現回数がちょうど1回の単語だけを結果として返す 実装例 # 珍しい単語を見つける関