0

This is the problem description:

Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:

Only one letter can be changed at a time Each transformed word must exist in the word list. Note that beginWord is not a transformed word.

Note:

Return an empty list if there is no such transformation sequence. All words have the same length. All words contain only lowercase alphabetic characters. You may assume no duplicates in the word list. You may assume beginWord and endWord are non-empty and are not the same.

Test case:

Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

Output:
[
  ["hit","hot","dot","dog","cog"],
  ["hit","hot","lot","log","cog"]
]

My issue:

To keep track of the path that the traversal takes to get to the current node, I'm trying to pass in a path array that is updated every time a new node is added to the queue. Currently, the code that updates the path is: q.append((word, level + 1, previous + [top])). For some reason, my path array isn't actually updating every time. What did I do wrong?

My code:

import collections
class Solution:
    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
        representations = {}
        for word in wordList:
            for i in range(len(word)):
                rep = word[:i] + "_" + word[i+1:]
                if word[:i] + "_" + word[i+1:] in representations:
                    representations[rep].append(word)
                else:
                    representations[rep] = [word]
        q = collections.deque()
        q.append((beginWord, 0, []))
        shortest = 0
        result = []
        visited = {}
        while q:
            top, level, previous = q.popleft()
            if top in visited: continue
            if not found:
                if top == endWord:
                    found = True
                    result.append(path)
                    shortest = level
                else:
                    visited[top] = True
                    for i in range(len(top)):
                        rep = word[:i] + "_" + word[i+1:]
                        for word in representations[rep]:
                            q.append((word, level + 1, previous + [top]))
                        representations[rep] = []
            else:
                if top == endWord:
                    result.append(previous + [top])
        return result
Community
  • 1
  • 1
aemach
  • 33
  • 2
  • what counts as a transformation? can letters be inserted or removed? – Ke Zhu Dec 03 '19 at 00:03
  • I strongly recommend you to look at the shortest distance algorithm - dijkstra's algorithm – Ke Zhu Dec 03 '19 at 00:11
  • A transformation is changing one letter. I know this can be solved with A*, but I'm trying to practice a faster to code solution (while maybe less efficient) for an interview – aemach Dec 03 '19 at 00:28
  • not A*, Dijkstra's algorithm serves the best in this case. – Ke Zhu Dec 03 '19 at 00:29

1 Answers1

0

this is solution in Dijkastra's algorithm. The first step is to build a graph. The second step is simply finding a path from start to end with the algorithm

import heapq

beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]

class Node:
    def __init__(self, word):
        self.word = word
        self.children = []
        self.visited = False
        self.last = None

    def __str__(self):
        s = ""
        s += self.word + "\n"
        s += ",".join([c.word for c in self.children]) + "\n"
        s += str(self.visited) + "\n"
        return s

def buildGraph(begin, end, wordList):

    all_words = wordList + [begin, end]
    all_words = list(dict.fromkeys(all_words))
    d = { w : Node(w) for w in all_words }

    for i, w in enumerate(all_words):
        for w2 in (all_words[i+1:]):
            if canHop(w, w2):
                d[w].children.append(d[w2])
                d[w2].children.append(d[w])

    return d

def canHop(w, w2):
    return len(list(filter(lambda x: x == False, [c == w2[i] for i, c in enumerate(w)]  ))) == 1

graph = buildGraph(beginWord, endWord, wordList)

s = graph[beginWord]
e = graph[endWord]

def findLadders(s, e, graph):
    scores = []
    heapq.heapify(scores)

    s.visited = True
    paths = [s]
    heapq.heappush(scores, (0, s.word))

    flag = False

    while len(scores) > 0:
        d, w = heapq.heappop(scores)
        n = graph[w]
        for c in n.children:
            if c.visited:
                continue
            c.last = n
            if c == e:
                flag = True
                break
            c.visited = True
            heapq.heappush(scores, (d+1, c.word))
        if flag:
            break
    result = []
    last = e
    while last is not None:
        result.append(last.word)
        last = last.last
    return result

print(findLadders(s,e,graph))
Ke Zhu
  • 207
  • 1
  • 9