93 lines
2.2 KiB
Go
93 lines
2.2 KiB
Go
package top100liked
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
// https://leetcode.cn/problems/word-search/description/?envType=study-plan-v2&envId=top-100-liked
|
|
|
|
func exist(board [][]byte, word string) bool {
|
|
w := []byte(word)
|
|
l := len(word)
|
|
m := len(board)
|
|
n := len(board[0])
|
|
// 下、右、上、左
|
|
move := [4][2]int{{1, 0}, {0, 1}, {-1, 0}, {0, -1}}
|
|
|
|
// 减枝让耗时降低了很多
|
|
|
|
var boardCnt [128]int // 覆盖 ASCII,字母在范围内
|
|
for _, row := range board {
|
|
for _, c := range row {
|
|
boardCnt[c]++
|
|
}
|
|
}
|
|
|
|
var wordCnt [128]int
|
|
for _, c := range w {
|
|
wordCnt[c]++
|
|
}
|
|
|
|
// 字符频次可行性预检。 扫一遍 board 统计各字符计数,若 word 中某字符出现次数超过 board 上的数量,直接 return false。
|
|
for _, char := range w {
|
|
if boardCnt[char] < wordCnt[char] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// 词序翻转剪枝(算法层面最大收益)。 统计 board 中 word[0] 和 word[l-1] 的出现次数,若首字符比尾字符更常见,就把 word 反转后再搜——从稀有端开始DFS,能在更浅层就剪掉大量无效分支。
|
|
if boardCnt[0] > boardCnt[len(boardCnt)-1] {
|
|
slices.Reverse(w)
|
|
}
|
|
|
|
var helper func(idx, row, col int) bool
|
|
helper = func(idx, row, col int) bool {
|
|
for _, v := range move {
|
|
new_row := row + v[0]
|
|
new_col := col + v[1]
|
|
if new_row >= 0 && new_row < m && new_col >= 0 && new_col < n && w[idx] == board[new_row][new_col] {
|
|
if idx == l-1 {
|
|
return true
|
|
}
|
|
board[new_row][new_col] = '#'
|
|
if helper(idx+1, new_row, new_col) {
|
|
return true
|
|
}
|
|
board[new_row][new_col] = w[idx]
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
for i, row := range board {
|
|
for j, col := range row {
|
|
if col == w[0] {
|
|
if l == 1 {
|
|
return true
|
|
}
|
|
board[i][j] = '#'
|
|
if helper(1, i, j) {
|
|
return true
|
|
}
|
|
board[i][j] = w[0]
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func Test(t *testing.T) {
|
|
fmt.Printf("%+v\n", exist([][]byte{{'A', 'B', 'C', 'E'}, {'S', 'F', 'C', 'S'}, {'A', 'D', 'E', 'E'}}, "ABCCED"))
|
|
}
|
|
|
|
func Test2(t *testing.T) {
|
|
fmt.Printf("%+v\n", exist([][]byte{{'A', 'B', 'C', 'E'}, {'S', 'F', 'C', 'S'}, {'A', 'D', 'E', 'E'}}, "SEE"))
|
|
}
|
|
|
|
func Test3(t *testing.T) {
|
|
fmt.Printf("%+v\n", exist([][]byte{{'A', 'B', 'C', 'E'}, {'S', 'F', 'C', 'S'}, {'A', 'D', 'E', 'E'}}, "ABCB"))
|
|
}
|