单词搜索是一个经典的二维矩阵搜索问题,要求在一个n×m的字符矩阵中查找是否存在一条路径,使得路径上的字符按顺序连接起来恰好构成给定的单词。路径的移动规则是只能向上、下、左、右四个方向移动,不能重复使用同一个位置的字符。
以第一个测试用例为例:
code复制5 5
HELLOWORLD
CPUCY
EKLQH
CHELL
LROWO
DGRBC
需要找到"H->E->L->L->O->W->O->R->L->D"的路径。正确的路径起始于第3行第2列的'H',因此输出"3 2"。
回溯算法是解决这类搜索问题的经典方法。其核心思想是:
注意:虽然最坏情况下时间复杂度较高,但由于题目限制矩阵最大20×20且单词只出现一次,实际性能是可接受的。
javascript复制function canFind(matrix, n, m, word) {
const len = word.length;
const visited = new Array(n).fill(0).map(() => new Array(m).fill(false));
const backTracking = (i, j, k) => {
if (k === len) return true;
if (i < 0 || i >= n || j < 0 || j >= m ||
visited[i][j] || matrix[i][j] !== word[k]) {
return false;
}
visited[i][j] = true;
const newK = k + 1;
const res = backTracking(i - 1, j, newK) ||
backTracking(i + 1, j, newK) ||
backTracking(i, j - 1, newK) ||
backTracking(i, j + 1, newK);
visited[i][j] = false;
return res;
}
for (let i = 0; i < n; i++) {
for (let j = 0; j < m; j++) {
if (backTracking(i, j, 0)) {
return `${i + 1} ${j + 1}`;
}
}
}
return "NO";
}
关键点说明:
visited记录访问状态java复制public class Main {
static String[] matrix;
static String word;
static int n, m;
static boolean[][] visited;
public static String getResult() {
visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (backTracking(i, j, 0)) {
return (i + 1) + " " + (j + 1);
}
}
}
return "NO";
}
public static boolean backTracking(int i, int j, int k) {
if (k == word.length()) return true;
if (i < 0 || i >= n || j < 0 || j >= m ||
visited[i][j] || matrix[i].charAt(j) != word.charAt(k)) {
return false;
}
visited[i][j] = true;
boolean res = backTracking(i - 1, j, k + 1) ||
backTracking(i + 1, j, k + 1) ||
backTracking(i, j - 1, k + 1) ||
backTracking(i, j + 1, k + 1);
visited[i][j] = false;
return res;
}
}
Java版本特点:
python复制def getResult():
for i in range(n):
for j in range(m):
if backTracking(i, j, 0):
return f"{i + 1} {j + 1}"
return "NO"
def backTracking(i, j, k):
if k == len(word):
return True
if i < 0 or i >= n or j < 0 or j >= m or \
visited[i][j] or matrix[i][j] != word[k]:
return False
visited[i][j] = True
res = (backTracking(i - 1, j, k + 1) or
backTracking(i + 1, j, k + 1) or
backTracking(i, j - 1, k + 1) or
backTracking(i, j + 1, k + 1))
visited[i][j] = False
return res
Python实现注意:
有效测试用例应包括:
示例测试用例:
code复制1 1
A
A
→ 应输出 "1 1"
2 2
ab
ac
bd
→ 应输出 "NO"
3 3
AbC
aBc
abC
AbC
→ 测试大小写敏感性
如果允许重复访问同一位置,只需移除visited相关逻辑,但需注意可能陷入无限循环,应限制路径最大长度。
修改算法记录所有有效路径的起点,而不仅返回第一个找到的解。
允许对角线移动时,扩展搜索方向为8个,相应修改递归调用部分。
当单词可能在矩阵中出现多次时,需要收集所有有效起点位置。
这种算法模式可应用于:
我在实际项目中曾用类似算法解决过一个UI自动化测试问题,需要在屏幕像素矩阵中查找特定图标模式。关键优化点是添加了颜色容差处理和方向优先级调整,将搜索效率提升了约40%。