BiruLyu
8/4/2017 - 3:03 AM

126. Word Ladder II(Slack01).py

from collections import defaultdict
from string import lowercase
class Solution(object):
    def getChildren(self, word, wordset):
        children = set([word])
        for i in range(len(word)):
            for char in lowercase:
                newword = word[:i] + char + word[i + 1:]
                if newword in wordset:
                    children.add(newword)
        return children

    def findLadders(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: List[List[str]]
        """
        wordset = set(wordList + [beginWord])
        if endWord not in wordset:
            return []

        parent, border = self.bidirectional(beginWord, endWord, wordset)
        if not border:
            return []

        paths = self.biGetAllPath(border, parent, beginWord, endWord)
        return paths

    def bidirectional(self, beginWord, endWord, wordset):
        fronts = [set([beginWord]), set([endWord])]
        visited = [set(), set()]
        prev = [defaultdict(list), defaultdict(list)]
        border = set()
        while all(fronts) and not border: 
            smaller = 0 if len(fronts[0]) < len(fronts[1]) else 1
            children = set()
            for node in fronts[smaller]:
                visited[smaller].add(node)
            for node in fronts[smaller]:
                for child in self.getChildren(node, wordset):
                    if child in fronts[not smaller]:
                        border.add(child)
                    if child not in visited[smaller]:
                        children.add(child)
                        prev[smaller][child].append(node)
            fronts[smaller] = children

        return prev, border

    def biGetAllPath(self, border, parent, beginWord, endWord):
        result = map(lambda x: [x], border)
        while result[0][0] != beginWord:
            result = [[daddy] + path for path in result for daddy in parent[0][path[0]]]

        while result[0][-1] != endWord:
            result = [ path + [child] for path in result for child in parent[1][path[-1]]]

        return result

import string
from collections import defaultdict
class Solution(object):
    def findLadders(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: List[List[str]]
        """
        wordList = set(wordList)
        if endWord not in wordList: return []
        if beginWord in wordList: wordList.remove(beginWord)
        if endWord in wordList: wordList.remove(endWord)
        beginSet, endSet = set([beginWord]), set([endWord])
        
        ansFound = False
        mp = defaultdict(list)
        while beginSet and endSet:
            if len(beginSet) < len(endSet):
                isBeginSmall, small, big = True, beginSet, endSet
            else:
                isBeginSmall, small, big = False, endSet, beginSet
            
            nextlvl = set([])
            for word in small:
                for i in range(len(word)):
                    for char in string.lowercase:
                        newword = word[:i] + char + word[i+1:]
                        
                        if newword in big or newword in wordList:
                            if newword in big: 
                                ansFound = True
                            nextlvl.add(newword)
                            if isBeginSmall: mp[word].append(newword)
                            else: mp[newword].append(word)
            
            if ansFound: break
            for word in nextlvl:
                wordList.remove(word)
            if isBeginSmall: beginSet = nextlvl
            else: endSet = nextlvl
        
        if not ansFound: return []
        
        res = [[beginWord]]
        while res[0][-1] != endWord:
            tmp = res
            res = []
            for line in tmp:
                for word in mp[line[-1]]:
                    res.append(line + [word])
        return res