1. 思路
- 先将单词构造成 Trie(前缀树)
- 然后两层循环遍历格子里的所有字母
- 每个被遍历到的字母作为单词的开头,去 Trie 匹配
3.1 如果不匹配,则直接下个格子开始
3.2 如果search
匹配到,则放入result
中
3.3 如果startWith
匹配到,则开始爬(move
方法)格子,有四个方向
3.4search
匹配成功必然startWith
,反过来不一定成立 - 由于每个格子只能用一次,所以记得打上标记
2. 代码(省略了 Trie 的代码,可以看思路里面的链接)
➥ JavaScript
/**
* @param {character[][]} board
* @param {string[]} words
* @return {string[]}
*/
var Trie = require('./Trie')
var findWords = function (board, words) {
// 例外情况判断
if (!board || board.length === 0 || !words || words.length === 0) return []
// 四个方向
const d = [
[-1, 0],
[1, 0],
[0, -1],
[0, 1]
]
const result = []
const trie = new Trie()
words.forEach(word => {
trie.insert(word)
})
const rows = board.length
const cols = board[0].length
/**
* str 是当前组成的字符串
*/
const move = (row, col, str) => {
if (board[row][col] !== '@') {
const tmp = board[row][col]
board[row][col] = '@' // 走过的格子打标记
str += tmp
// indexOf 是为了判重,有些单词可以从几个方向构建成功
if (trie.search(str) && result.indexOf(str) < 0) {
result.push(str)
}
if (trie.startsWith(str)) {
// 四个方向
for (let i = 0; i < 4; i++) {
const nextRow = row + d[i][0]
const nextCol = col + d[i][1]
// 下一个格子的合法性校验
if (
nextRow > -1 &&
nextCol > -1 &&
board[nextRow] &&
board[nextRow][nextCol]
) {
move(nextRow, nextCol, str)
}
}
}
board[row][col] = tmp // 还原标记
}
}
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
move(row, col, '')
}
}
return result
};
3. 结果
上面这个记录是我同一段代码第二次提交的,第一次提交的执行用时只有 272ms,内存消耗差不多。
总之做个参考吧,谢谢阅读。