题目
给定一个单词集合(没有重复),找出其中所有的 单词方块。
一个单词序列形成了一个有效的单词方块的意思是指从第 k
行和第 k
列 (0 ≤ k < max(行数, 列数)
) 来看都是相同的字符串。
例如,单词序列 ["ball", "area", "lead", "lady"]
形成了一个单词方块,因为每个单词从水平方向看和从竖直方向看都是相同的。
b a l l
a r e a
l e a d
l a d y
注意:
- 单词个数大于等于 1 且不超过 500。
- 所有的单词长度都相同。
- 单词长度大于等于 1 且不超过 5。
- 每个单词只包含小写英文字母 a-z。
示例 1:
输入:
["area","lead","wall","lady","ball"]
输出:
[
[ "wall",
"area",
"lead",
"lady"
],
[ "ball",
"area",
"lead",
"lady"
]
]
解释:
输出包含两个单词方块,输出的顺序不重要,只需要保证每个单词方块内的单词顺序正确即可。
示例 2:
输入:
["abat","baba","atan","atal"]
输出:
[
[ "baba",
"abat",
"baba",
"atan"
],
[ "baba",
"abat",
"baba",
"atal"
]
]
解释:
输出包含两个单词方块,输出的顺序不重要,只需要保证每个单词方块内的单词顺序正确即可。
方案一
class Trie:
def __init__(self, words=[]):
self.lookup = {}
for word in words:
self.add(word)
def add(self, word: str) -> None:
"""
Inserts a word into the trie.
"""
node = self.lookup
for c in word:
if c not in node:
node[c] = {}
node = node[c]
node['is_word'] = True
def has(self, word: str) -> bool:
"""
Returns if the word is in the trie.
"""
node = self.lookup
for c in word:
if c not in node:
return False
node = node[c]
# 判断是否是单词
if 'is_word' in node:
return True
return False
def startsWith(self, prefix: str, limit: int) -> [str]:
"""
Returns if there is any word in the trie that starts with the given prefix and length equal limit.
需要保证 len(prefix) > limit,在不做特殊处理
"""
node = self.lookup
index = 0
for c in prefix:
index += 1
if c not in node:
return []
node = node[c]
return self._getAllWords(node, prefix, limit)
def _getAllWords(self, node, prefix, limit):
ret = []
if len(prefix) > limit:
return []
if len(prefix) == limit and "is_word" in node:
return [prefix]
for key in node:
ret.extend(self._getAllWords(node[key], prefix + key, limit))
return ret
class Solution:
def __init__(self):
self.trie = Trie()
def wordSquares(self, words: List[str]) -> List[List[str]]:
if not words:
return []
for word in words:
self.trie.add(word)
# 比如有[ball],我们知道单词方块是 4X4,换句话说每个单词长度都为4,其次下个单词是a字母开头的。
# 假如我们找到一个a开头长度为4单词,变成[ball, area],那么第三个单词的前缀是le长度为4单词,依次类推。
ret = []
def backtrack(item: [str]):
'''每一个方块'''
if len(item) == len(item[0]):
ret.append(item)
return
# 获取当前的前缀
prefix = ""
for it in item:
prefix += it[len(item)] # 因为是方块,所以 len(item) == 当前方块的高
# 获取前缀是 prefix 长度为 len(item[0]) 的单词
prefix_words = self.trie.startsWith(prefix, len(item[0]))
for pw in prefix_words:
backtrack(item + [pw])
for word in words:
backtrack([word])
return ret
原文
https://leetcode-cn.com/explore/learn/card/trie/168/practical-application-ii/653/