Given an
m x n
board
of characters and a list of strings words
, return all words on the board.Each word must be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
Example 1:
Input: board = [[“o”,”a”,”a”,”n”],[“e”,”t”,”a”,”e”],[“i”,”h”,”k”,”r”],[“i”,”f”,”l”,”v”]], words = [“oath”,”pea”,”eat”,”rain”]
Output: [“eat”,”oath”]
Example 2:
Input: board = [[“a”,”b”],[“c”,”d”]], words = [“abcb”]
Output: []
Constraints:
m == board.length
n == board[i].length
1 <= m, n <= 12
board[i][j]
is a lowercase English letter.`1 <= words.length <= 3 104
*
1 <= words[i].length <= 10*
words[i]consists of lowercase English letters.
* All the strings of
words` are unique.算法思路:
N/A
注意事项:
- 用Trie来保存单词列表,这样每次DFS的每一步都可以O(1)时间知道是否和单词吻合,而不是O(n)
- 难点1: Trie的接口有startswith, search, insert,仅insert可以用,其他两个不支持与DFS同步搜索。所以要写一个新函数:其实修改startsWith将for循环去掉当然DFS的API也要改,去掉word, word_index加入trie, trie_node, path, res
- TLE错误,因为比如矩阵为[abc],单词列表为abc, abc, abc,这样abc加入到结果后就不应该再搜abc,因为结果不能重且效率大打折扣。如果找到了单词,就应该将它从Trie中去掉,避免无谓的搜索,条件是该节点children长度为0,就父节点就将key删除。如果还有儿子节点只能标记is_end为False。Line 29 - 31和35 - 36
Python代码:
1 | OFFSETS = [(0, 1), (1, 0), (-1, 0), (0, -1)] |
上述代码比较复杂,可以先写这个LTE版本, 它在最后结果去重,但是对于重复单词会LTE,如[‘a’, … ‘a’]. 所以演变成最优版本,需要删除Trie的节点
Python代码:
1 | def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: |
算法分析:
时间复杂度为O(n2*4*3L-1)
,空间复杂度O(n2)
, n是矩阵长度,L是最大单词长度.
3是因为访问过的节点不合法,也就是来的节点不能再走一次,所以只能3个方向,第一个可以4个方向,其他步是3个方向
有一个方法是不用Trie而是将单词所有prefix放入到set中,但会TLE,因为时间复杂度为O(n23n*n)
,它不会剪枝,从顶点出发,最差情况是z型走完board,此时路径长度为n*n.