Pregunta LeetCode 127-Word Solitaire-Python

tema

Dadas dos palabras (beginWord y endWord) y un diccionario , encuentre la longitud de la secuencia de conversión más corta desde beginWord hasta endWord. La conversión debe seguir las siguientes reglas:

  1. Solo se puede cambiar una letra por conversión.
  2. La palabra intermedia en el proceso de conversión debe ser una palabra del diccionario.

Descripción:

  • No existe tal secuencia de conversión y se devuelve 0.
  • Todas las palabras tienen la misma longitud.
  • Todas las palabras constan únicamente de letras minúsculas.
  • No hay palabras duplicadas en el diccionario.
  • Puede asumir que beginWord y endWord no están vacíos y no son lo mismo.
输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出: 5

解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
     返回它的长度 5。

Solución oficial: primera búsqueda en amplitud + mapa optimizado 1

La idea general: buscar la secuencia más corta ==> pensar en el modelo gráfico ==> pensar en la amplitud primero buscar

Ideas para la construcción de gráficos:

  1. ¿Cómo elegir un nodo? Trate las palabras como nodos
  2. ¿Cómo seleccionar nodos adyacentes? Las palabras que difieren en una sola letra se consideran nodos adyacentes.
  3. ¿Cómo elegir un diagrama de construcción? Construya un gráfico no dirigido para conectar nodos adyacentes entre sí

Icono de efecto:Alt

algoritmo

Explicación del código del método uno:

Etapa de mapeo

  1. Crear nodo: para usar palabras para representar nodos, asigne números a las palabras (beginWord, WordList) y use tablas hash ( diccionarios ) para implementar un mapeo de palabra a número("Palabra": id)
  2. El problema del mapeo directo: enumere la combinación de cada par de palabras y determine si están exactamente separadas por un carácter. La eficiencia es baja, así que use mapeo optimizado , es decir, use nodos virtuales
  3. Nodo virtual:
虚拟节点。对于单词 hit,我们创建三个虚拟节点 *it、h*t、hi*,
并让 hit 向这三个虚拟节点分别连一条边即可。如果一个单词能够转化为 hit,
那么该单词必然会连接到这三个虚拟节点之一。对于每一个单词,
我们枚举它连接到的虚拟节点,
把该单词对应的 id 与这些虚拟节点对应的 id 相连即可。

Explicación de ejemplo: para palabras como "hit" y "hot" que difieren en un carácter, conecte el nodo virtual "h * t" en uno de los tres bordes señalados por "hit" juntos. Nodos de palabras que tienen una letra menos unos de otros están conectados.
Nota: Debido a que se agrega el nodo virtual, la distancia que obtenemos es el doble de la longitud de la ruta más corta real. El resultado final debe devolver el resultado de la distancia actual generalmente menos uno

Amplitud primer recorrido

En esta pregunta, use una cola de dos vías para lograr un recorrido de amplitud primero:

  1. dis = [float ("inf")] * Número total de nodos, la prueba inicial define la distancia entre beginWord y cada nodo para que esté vacío
  2. Inserte el nodo beginWord en la cola. Si es el nodo adyacente del nodo beginWord, cambie el valor de este nodo en dis a "1" y agregue el nodo a la cola.
  3. Repita el recorrido primero en amplitud hasta que se encuentre el nodo endWord.
    Ejemplo Figura 2
    Alt

Código

import collections
from collections import defaultdict
class Solution:
    def ladderLength( beginWord, endWord, wordList) -> int:
        def addWord(word: str):
            # 计数结点总数
            if word not in wordId:
                nonlocal nodeNum    # nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量。表示在一个总def中做同一变量
                # print(nodeNum)
                wordId[word] = nodeNum
                # print(word)    # word 表示单词
                nodeNum += 1
                
        
        def addEdge(word: str):
            # 创建图
            addWord(word)
            id1 = wordId[word]    # id2是真实结点的结点编号
            chars = list(word)
            for i in range(len(chars)):
                tmp = chars[i]
                chars[i] = "*"
                newWord = "".join(chars)    # 组成新的单词
                addWord(newWord)    # 为虚拟单词建立虚拟结点
                id2 = wordId[newWord]    # id2是虚拟结点的结点编号
                edge[id1].append(id2)    # edge是字典,将此虚拟结点的词连接真实结点中
                # print(edge)
                edge[id2].append(id1)    # 双向连接,形成双向图
                chars[i] = tmp    # 恢复单词

        wordId = dict()
        edge = collections.defaultdict(list)    # Python内建字典类(dict)的一个子类 (class list)表示边 
        nodeNum = 0
        
        # --------------------------------------------------------
        for word in wordList:
            addEdge(word)    # 对单词字典列表中的单词插入边与结点
        
        addEdge(beginWord)    # 将首个单词加入图中与对应虚拟结点加入图中
        # 创建图完毕
        # --------------------------------------------------------
        
        # 当给出结尾词不在字典中,必无最短路径
        if endWord not in wordId:
            return 0
        
        dis = [float("inf")] * nodeNum
        beginId, endId = wordId[beginWord], wordId[endWord]    # 获得开始结束单词的id
        # print(beginId, endId)
        dis[beginId] = 0    # 将距离中的beginId设置为 0

        que = collections.deque([beginId])    # 实现双端队列
        while que:
            x = que.popleft()
            if x == endId:
                return dis[endId] // 2 + 1
            for it in edge[x]:
                # 从开始结点开始寻找,实现广度优先遍历
                if dis[it] == float("inf"):
                    dis[it] = dis[x] + 1
                    print(it,dis[it])
                    que.append(it)
        
        return 0


  1. https://leetcode-cn.com/problems/word-ladder/solution/dan-ci-jie-long-by-leetcode-solution/ ↩︎

  2. https://leetcode-cn.com/problems/word-ladder/solution/bfsjie-jue-yi-quan-yi-quan-wang-wai-kuo-san-by-sdw/ ↩︎

Supongo que te gusta

Origin blog.csdn.net/qq_42388742/article/details/109521195
Recomendado
Clasificación