边工作边刷题:70天一遍leetcode: day 66

Word Search II

要点:

  • board作为visited。为什么dfs最后要unset visited?visited的意义是在当前的dfs stack内,对这题也就是当前path。下一层dfs之后,当前path结果已经得到,但是改点还可能在其他的path上,所以要把visited unset。类似于有向图dfs。
  • trie: 一个buildtrie function即可。search和dfs是一起的。
  • trie和层次:当前node是当前处理字符的前一个点,所以进入dfs才开始处理当前字符(or board[i][j]),否则会出现["a"], dict=["a”]返回[]的错误。

错误点:

  • 类似grid渲染,每个点都可能是起点,所以要loop每个点然后dfs
  • 简单dedup:当找到一个词以后,将isLeaf设为False。(7/8/16) 优化 1:直接用word or None表示leaf,这样不用在dfs中记录path和最后重构单词。
  • 优化2:每层dfs call之前做边界检查,省了function call的cost:从TLE提高到beat 8%
  • 优化3:用map记录每个结点的neighbors而不是用[]*26,从8%提高到beat 50.75%
  • 优化4:直接把board size m, n pass in,而不是on-the-fly计算,从50.75% => 73.88%
class Solution(object):
    class TrieNode:
        def __init__(self):
            # self.isLeaf = False
            # self.neighbors = [None]*26
            self.neighbors = {} # use map instead of list*26 from 8% to 50.75%
            self.word = None

    @staticmethod
    def buildDict(words):
        root = Solution.TrieNode()
        for w in words:
            cur = root
            #for i in xrange(len(w)):
            for c in w:
                # c = ord(w[i])-ord('a')
                # if not cur.neighbors[c]:
                #     cur.neighbors[c]=Solution.TrieNode()
                cur = cur.neighbors.setdefault(c, Solution.TrieNode())
                # cur=cur.neighbors[c]
            cur.word = w # optimal 2: root.word is not the TLE cause
        return root

    def findWords(self, board, words):
        """
        :type board: List[List[str]]
        :type words: List[str]
        :rtype: List[str]
        """
        def dfs(board, i, j, root, solutions, m, n):
            # m = len(board)
            # n = len(board[0])
            # print i,j
            
            c = board[i][j]
            if not (c and c in root.neighbors):
                return
            
            board[i][j], root = None, root.neighbors[c]
            
            if root.word:
                solutions.append(root.word)
                root.word = None
            
            # if i>=m or j>=n or i<0 or j<0:
            #   return
            
            # c = board[i][j]
            #print c
            #if board[i][j]!='#' and root.neighbors[ord(c)-ord('a')]:
            #    rn = root.neighbors[ord(c)-ord('a')]
                # resw.append(board[i][j])
            #    board[i][j]='#'
            if i+1<m: # optimal 1: check before funciton call beat 8%
                dfs(board, i+1, j, root, solutions, m, n)
            if i-1>=0:
                dfs(board, i-1, j, root, solutions, m, n)
            if j+1<n:
                dfs(board, i, j+1, root, solutions, m, n)
            if j-1>=0:
                dfs(board, i, j-1, root, solutions, m, n)
            #     # resw.pop()
            # for x, y in ((0, -1), (-1, 0), (0, 1), (1, 0)):
            #     ii, jj = i + x, j + y
            #     if 0 <= ii < m and 0 <= jj < n:
            #         dfs(board, ii, jj, root, solutions)
            board[i][j]=c
        
        root = Solution.buildDict(words)
        solutions = []
        # resw = []
        m = len(board)
        n = len(board[0])
        for i in xrange(m):
            for j in xrange(n):
                dfs(board, i, j, root, solutions, m, n)
        return solutions
            
posted @ 2016-06-06 05:26  absolute100  阅读(99)  评论(0编辑  收藏  举报