矩阵中的路径

问题要求

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。

示例:

输入:board =
(“A”,“B”,“C”,“E”),
(“S”,“F”,“C”,“S”),
(“A”,“D”,“E”,“E”),
//board定义一个二维数组,此处( 等同于花括号,由于与markdown内置标签冲突,故使用括号代替花括号。
word = “ABCCED”
输出:true

问题分析

本问题是典型的矩阵搜索问题,可使用 深度优先搜索(DFS)+ 剪枝 解决。

算法原理

  • 深度优先搜索: 可以理解为暴力法遍历矩阵中所有字符串可能性。DFS 通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推。
  • 剪枝: 在搜索中,遇到 这条路不可能和目标字符串匹配成功 的情况(例如:此矩阵元素和目标字符不同、此元素已被访问),则应立即返回,称之为 可行性剪枝

算法剖析

  • 递归参数: 当前元素在矩阵 board 中的行列索引 i 和 j ,当前目标字符在 word 中的索引 k 。
  • 终止条件:
    返回 false : ① 行或列索引越界 或 ② 当前矩阵元素与目标字符不同 或 ③ 当前矩阵元素已访问过 (③ 可合并至 ② ) 。
    返回 true : 字符串 word 已全部匹配,即 k = length(word) - 1 。
  • 递推工作:
    标记当前矩阵元素: 将 board[i][j]值暂存于变量 tmp ,并修改为字符 ‘/’ ,代表此元素已访问过,防止之后搜索时重复访问。 搜索下一单元格: 朝当前元素的 上、下、左、右 四个方向开启下层递归,使用 或 连接 (代表只需一条可行路径) ,并记录结果至 res 。 还原当前矩阵元素: 将 tmp 暂存值还原至 board[i][j] 元素。
  • 回溯返回值: 返回 res ,代表是否搜索到目标字符串。

代码实现

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Path_in_Mat {
public boolean exists(char[][] boardpanel,String word){
char[] words=word.toCharArray();
for(int i=0;i<boardpanel.length;i++){
for(int j=0;j<boardpanel[0].length;j++){
if(dfs(boardpanel,words,i,j,0)) return true;
}
}
return false;
}
public boolean dfs(char[][] boardpanel,char[] word,int i,int j,int k){
if(i<0||i>=boardpanel.length||j<0||j>=boardpanel[0].length||boardpanel[i][j]!=word[k]) return false;
if(k==word.length-1) return true;
char temp=boardpanel[i][j];
boardpanel[i][j]='/';//将访问过的元素标记为/,以防再次访问。
boolean res=dfs(boardpanel,word,i+1,j,k+1)||dfs(boardpanel,word,i-1,j,k+1)||
dfs(boardpanel,word,i,j+1,k+1)||dfs(boardpanel,word,i,j-1,k+1);
boardpanel[i][j]=temp;
return res;
}
public static void main(String[] args){
char[][] boardpanel={{'a','b','c','e'},{'s','f','c','s'},{'a','d','e','e'}};
String words="abcced";
Path_in_Mat path_in_mat=new Path_in_Mat();
System.out.println(path_in_mat.exists(boardpanel,words));
}
}

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
//vector<vector<char>>& board为 char型二维数组
if(board.size() == 0) return false;
for (int i=0;i<board.size();i++){
for(int j=0;j<board[0].size();j++){
if (dfs(board,word,i,j,0)){
return true;
}
}
}
return false;
}

bool dfs(vector<vector<char>>& board, string& word, int i,int j,int length){
//string& word表示word的引用;另c++中char型数组和string等价。
if(i>=board.size()||j>=board[0].size()||i<0||j<0||length>=word.size()||word[length]!=board[i][j]){
return false;
}
if(length==word.size()-1&&word[length]==board[i][j]){
return true;
}
char temp=board[i][j];
board[i][j]='0';
bool flag=dfs(board,word,i,j+1,length+1)||dfs(board,word,i,j-1,length+1)||dfs(board,word,i+1,j,length+1)||dfs(board,word,i-1,j,length+1);
board[i][j]=temp;
return flag;
}
};