难度:中等
题目
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
示例 1:
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
示例 2:
输入:board = [[“a”,“b”],[“c”,“d”]], word = “abcd”
输出:false
提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
解答
思路:回溯法,不用递归所以代码比较长。有4个状态需要保存,分别是已找到点的x,y,这个点在上一个点的哪个方向,已经找到了几个点(这个可以从第一或第二个状态退出来,可以优化)。
| 序号 | 步骤 |
|---|---|
| 1 | 找到第一个点的位置 |
| 2 | 在上一个点的周围寻找 |
| 3 | 找不到回溯,找的到则继续寻找下一个点 |
| 序号 | 知识点 |
|---|---|
| 1 | 二维数组初始化vector<vector> used(a,vector(b,0) |
| 2 | |和||的区别,|前后两个条件都要执行,||当前面一个成立时,后面那个条件不执行 |
| 3 | stack的使用pop,push,top |
| 4 | switch case的使用 |
| 复杂度 | O |
|---|---|
| 时间复杂度 | |
| 空间复杂度 | O(n2) |
代码
class Solution {
private:
int firstRow=0,firstColumn=0;
public:
bool exist(vector<vector<char>>& board, string word) {
// 回溯
if(!word.size()){
return true;
}
if(!board.size()){
return false;
}
const int boardRow=board.size();
const int boardColumn=board[0].size();
const int size=word.size();
int index=0;
stack<int> myrow;
stack<int> mycolumn;
vector<vector<char>> used(board.size(),vector<char>(board[0].size(),0));//保存上次在哪个方向找到的 1 2 3 4 分别代表左上右下
// 找到第一个
bool isFindFirst=false;
while(index<size){
if(!isFindFirst){
isFindFirst=isFindFirstPoint(board,word[0],myrow,mycolumn,used);
if(!isFindFirst){
return false;
}
else{
index++;
continue;
}
}
// 栈顶四个方向搜索 左上右下
if(isFindNextPoint(board, word[index],myrow,mycolumn,used)){
index++;
}
else{
index--;
}
if(index==0){
isFindFirst=false;//重新找起点
}
}
return true;
}
bool isFindNextPoint(const vector<vector<char>>& board, const char & Point,stack<int>& row,stack<int>& column,vector<vector<char>>& used){
int topRow=row.top(),topColumn=column.top();
switch(++used[topRow][topColumn]){
case 1:
if(isValidAndEqual(board,Point,topRow,topColumn-1,used)){
row.push(topRow);
column.push(topColumn-1);
used[topRow][topColumn]=1;
break;
}
case 2:
if(isValidAndEqual(board,Point,topRow-1,topColumn,used)){
row.push(topRow-1);
column.push(topColumn);
used[topRow][topColumn]=2;
break;
}
case 3:
if(isValidAndEqual(board,Point,topRow,topColumn+1,used)){
row.push(topRow);
column.push(topColumn+1);
used[topRow][topColumn]=3;
break;
}
case 4:
if(isValidAndEqual(board,Point,topRow+1,topColumn,used)){
row.push(topRow+1);
column.push(topColumn);
used[topRow][topColumn]=4;
break;
}
default:
// 这个点没用回溯
row.pop();
column.pop();
used[topRow][topColumn]=0;
return false;
}
return true;
}
bool isValidAndEqual(const vector<vector<char>>& board,const char & Point,int nowRow,int nowColumn,vector<vector<char>>& used){
// cout<<"1: findNextPoint"<<nowRow<<" "<<nowColumn<<" "<<Point<<endl;
if(nowRow<0||nowRow>=board.size()||nowColumn<0||nowColumn>=board[0].size()||used[nowRow][nowColumn]!=0){
return false;
}
if(board[nowRow][nowColumn]==Point){
// cout<<"findNextPoint"<<nowRow<<" "<<nowColumn<<" "<<Point<<endl;
return true;
}
return false;
}
bool isFindFirstPoint(const vector<vector<char>>& board, const char & firstPoint,stack<int>& row,stack<int>& column,vector<vector<char>>& used){
cout<<"firstRow"<<firstRow<<firstColumn<<endl;
const int boardRow=board.size();
const int boardColumn=board[0].size();
while(1){
if(firstColumn>=boardColumn){
firstRow++;
firstColumn=0;
}
if(firstRow>=boardRow){
break;
}
if(board[firstRow][firstColumn]==firstPoint){
row.push(firstRow);
column.push(firstColumn);
// cout<<"firstRowColumn"<<firstRow<<" "<<firstColumn<<endl;
firstColumn++;//防止下次进来找到同一个点
return true;
}
firstColumn++;
}
return false;
}
};
本文介绍了一种使用回溯法在矩阵中查找特定字符串路径的算法。通过实例演示了如何从矩阵任意位置开始,向上下左右移动,寻找指定字符串的所有字符路径,确保路径不重复经过同一格。
432

被折叠的 条评论
为什么被折叠?



