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

【Python】1文字ずつ変更して別の単語へ到達する最小ステップ数を求めるプログラム

問題の概要

単語のリスト「dictionary」と、2つの文字列「start」「end」が与えられます。startからendへ向かって、一度に1文字だけ変更しながら到達することを目指します。ただし、途中で作られるすべての単語はdictionaryに含まれている必要があり、大文字と小文字は区別されます。このとき、endに到達するまでに必要な最小ステップ数を求めます。到達が不可能な場合は-1を返します。

例えば、dictionary = ["may", "ray", "rat"]、start = "rat"、end = "may" の場合、出力は3になります。「rat → ray → may」というパスを選べば、3ステップで目的の単語に到達できるためです。

解き方:幅優先探索(BFS)を使う

この種の「最短手数を求める」問題は、幅優先探索(BFS)が最適です。BFSは開始地点から近い順に状態を展開していくため、最初にendに到達した時点の手数が必ず最小値になります。

具体的な手順は以下の通りです。

  1. dictionaryを重複のないセット(set)に変換します。これにより、存在確認と削除を高速に行えます。
  2. (start, 1) というペアを持つ両端キュー(deque)を用意します。第2要素は現在までの手数です。
  3. キューが空になるまで次を繰り返します。
    • キューの左端から (word, distance) を取り出します。
    • wordがendと一致していれば、distanceを答えとして返します。
    • wordの各位置 i について、アルファベット26文字それぞれの文字 c で置き換えた next_word = word[:i] + c + word[i+1:] を生成します。
    • next_wordがdictionaryに存在する場合は、dictionaryから削除(訪問済みマークの代わり)し、(next_word, distance + 1) をキューの末尾に追加します。
  4. キューが空になってもendに到達できなければ、-1を返します。

訪問済みの単語をdictionaryから削除しておくことで、同じ単語を何度も処理する無駄を防ぎ、無限ループも回避できます。

Pythonでの実装例

以下が実際の実装コードです。

from collections import deque
class Solution:
    def solve(self, dictionary, start, end):
        dictionary = set(dictionary)
        q = deque([(start, 1)])
        while q:
            word, distance = q.popleft()
            if word == end:
                return distance
            for i in range(len(word)):
                for c in "abcdefghijklmnopqrstuvwxyz":
                    next_word = word[:i] + c + word[i + 1 :]
                    if next_word in dictionary:
                        dictionary.remove(next_word)
                        q.append((next_word, distance + 1))
        return -1
ob = Solution()
dictionary = ["may", "ray", "rat"]
start = "rat"
end = "may"
print(ob.solve(dictionary, start, end))

入力

["may", "ray", "rat"], "rat", "may"

出力

3

計算量について

単語の長さをL、辞書の単語数をNとすると、各単語につき L × 26 個の候補を生成するため、時間計算量はおおよそ O(N × L × 26) となります。セットによる存在確認がO(1)で行える点が、この実装の効率化のポイントです。

  1. Pythonで8パズルの最短手数を求めるプログラムを実装する方法

    8パズルは、3×3の盤面に0から8までの重複しない数字が配置された古典的なスライディングパズルです。0(空白)は上下左右の隣接マスと入れ替えることができ、すべての数字を昇順に並べ替えた状態(0, 1, 2, ..., 8)を目標とします。本記事では、初期盤面からゴール状態へ到達するまでの最小手数を求めるPythonプログラムを紹介します。 問題の例 例として、次のような盤面が入力された場合を考えます。 312 475 680 この場合の出力は 4 になります。つまり、4回の入れ替え操作でゴール状態に到達できることを意味します。 解法の考え方:幅優先探索(BFS) この問題は幅優

  2. Pythonでリスト内の最大値を見つける方法|sort()とmax()の2つのアプローチ

    この記事では、リストの中から最大の数値を見つけるための解決策とアプローチについて詳しく解説します。問題の概要数値のリストが与えられたとき、その中から最大の要素を見つけ出す必要があります。Pythonでは、主に以下の2つの方法でこれを実現できます。ソート(並べ替え)を利用する方法組み込み関数 max() を利用する方法アプローチ1:sort() 関数を使う方法リストを sort() メソッドで昇順に並べ替えると、リストの最後の要素(インデックス -1)が必ず最大値になります。サンプルコードlist1 = [18, 65, 78, 89, 90] list1.sort() # メイン処理 prin