2021-09-05:单词搜索 II。给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words,找出所有同时在二维网格和字典中出现的单词。单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。力扣212。

福大大 答案2021-09-05:

前缀树。

代码用golang编写。代码如下:

package main

import "fmt"

func main() {
    board := [][]byte{{'o', 'a', 'a', 'n'}, {'e', 't', 'a', 'e'}, {'i', 'h', 'k', 'r'}, {'i', 'f', 'l', 'v'}}
    words := []string{"oath", "pea", "eat", "rain"}
    ret := findWords(board, words)
    fmt.Println(ret)
}

type TrieNode struct {
    nexts []*TrieNode
    pass  int
    end   bool
}

func NewTrieNode() *TrieNode {
    ans := &TrieNode{}
    ans.nexts = make([]*TrieNode, 26)
    ans.pass = 0
    ans.end = false
    return ans
}

func fillWord(head *TrieNode, word string) {
    head.pass++
    chs := []byte(word)
    index := 0
    node := head
    for i := 0; i < len(chs); i++ {
        index = int(chs[i] - 'a')
        if node.nexts[index] == nil {
            node.nexts[index] = NewTrieNode()
        }
        node = node.nexts[index]
        node.pass++
    }
    node.end = true
}

func generatePath(path []byte) string { //LinkedList<Character>
    str := make([]byte, len(path))
    index := 0
    for _, cha := range path {
        str[index] = cha
        index++
    }
    return string(str)
}

func findWords(board [][]byte, words []string) []string {
    head := NewTrieNode() // 前缀树最顶端的头
    set := make(map[string]struct{})
    for _, word := range words {
        if _, ok := set[word]; !ok {
            fillWord(head, word)
            set[word] = struct{}{}
        }
    }
    // 答案
    ans := make([]string, 0)
    // 沿途走过的字符,收集起来,存在path里
    path := make([]byte, 0)
    for row := 0; row < len(board); row++ {
        for col := 0; col < len(board[0]); col++ {
            // 枚举在board中的所有位置
            // 每一个位置出发的情况下,答案都收集
            process(board, row, col, &path, head, &ans)
        }
    }
    return ans
}

// 从board[row][col]位置的字符出发,
// 之前的路径上,走过的字符,记录在path里
// cur还没有登上,有待检查能不能登上去的前缀树的节点
// 如果找到words中的某个str,就记录在 res里
// 返回值,从row,col 出发,一共找到了多少个str
func process(board [][]byte, row int, col int, path *[]byte, cur *TrieNode, res *[]string) int {
    cha := board[row][col]
    if cha == 0 { // 这个row col位置是之前走过的位置
        return 0
    }
    // (row,col) 不是回头路 cha 有效

    index := cha - 'a'
    // 如果没路,或者这条路上最终的字符串之前加入过结果里
    if cur.nexts[index] == nil || cur.nexts[index].pass == 0 {
        return 0
    }
    // 没有走回头路且能登上去
    cur = cur.nexts[index]
    *path = append(*path, cha) // 当前位置的字符加到路径里去
    fix := 0                   // 从row和col位置出发,后续一共搞定了多少答案
    // 当我来到row col位置,如果决定不往后走了。是不是已经搞定了某个字符串了
    if cur.end {
        *res = append(*res, generatePath(*path))
        cur.end = false
        fix++
    }
    // 往上、下、左、右,四个方向尝试
    board[row][col] = 0
    if row > 0 {
        fix += process(board, row-1, col, path, cur, res)
    }
    if row < len(board)-1 {
        fix += process(board, row+1, col, path, cur, res)
    }
    if col > 0 {
        fix += process(board, row, col-1, path, cur, res)
    }
    if col < len(board[0])-1 {
        fix += process(board, row, col+1, path, cur, res)
    }
    board[row][col] = cha
    //path.pollLast()
    *path = (*path)[0 : len(*path)-1]
    cur.pass -= fix
    return fix
}

执行结果如下:
图片


左神java代码