给定一个字符矩阵和一个单词, 确定该单词是否存在于该矩阵中。
- 当找到一个连续的字母序列,使得该序列组成的单词和给定的单词相同时,则单词存在于矩阵中。找不到则不存在。
- 在单词中相邻的两个字母,必须在矩阵中横向或纵向相邻。
比如,设
board =[
[“ABCE”],
[“SFCS”],
[“ADEE”]
]
word = “ABCCED”, -> returns true,
word = “SEE”, -> returns true,
word = “ABCB”, -> returns false.
题目的提示是采用回溯法。回溯给我的感觉和深度优先搜索非常像,但是有种细微的区别说不上来。。(还是研究不到家。。⊙﹏⊙b汗)
设两个栈s和visited,s用于保存即将探索的点,visited用于保存搜索路劲和搜索进度。
设起始搜索点为start,首先将start入栈s。
假设当前匹配的字符位置i。
搜索算法描述如下:
- 取出s栈顶元素p, (p.i,p.j) 是坐标,p.len是在p点已经匹配的单词长度。若栈为空,转7
- 若i和p.len相等,转3(深搜);若不相等,转6(回溯)。
- 若board[p.i][p.j]和word[i]相等,则i++,p.len++;若不相等,转1。
- 将p入栈visited,设置p点为已访问。
- 将p的上下左右未访问过的点入栈s,四个点的len均设为p.len,转1。
- 将visited不断出栈,将出栈位置设为未访问,并使i=i-1,直到出栈元素的len和i相等或者栈为空为止。然后转3。
- 若i和单词长度相等,则返回true,否则返回false。
实现代码如下
struct point{
int i;
int j;
int len;
point(int __i, int __j, int __len):i(__i), j(__j), len(__len){}
};
class Solution {
public:
int row;
int col;
void push(int i, int j, int len, stack<point>& s, vector<vector<int> >& visit_flag){
if(i >= 0 && i < row && j>=0 && j< col && visit_flag[i][j] != 1){
s.push(point(i, j, len));
}
}
void push_point(const point& p, stack<point>& s, vector<vector<int> >& visit_flag){
push(p.i, p.j-1, p.len, s, visit_flag);
push(p.i-1, p.j, p.len, s, visit_flag);
push(p.i, p.j+1, p.len, s, visit_flag);
push(p.i+1, p.j, p.len, s, visit_flag);
}
bool search(vector<vector<char>>& board, string& word, point start){
stack<point> s;
stack<point> visited;
vector<vector<int> > visit_flag(board.size(), vector<int>(board[0].size(), 0));
point p = start;
int len = word.size(), i = 0;
s.push(p);
while(!s.empty() && i < len){
p = s.top();s.pop();
while(!visited.empty() && i != p.len){
//backtracking
point tmp = visited.top();
visited.pop();
visit_flag[tmp.i][tmp.j] = 0;
cout<<"back"<<endl;
print(visit_flag);
i--;
}
//if match?
if(board[p.i][p.j] == word[i]){
i++;
p.len++;
push_point(p, s, visit_flag);
visited.push(p);
visit_flag[p.i][p.j] = 1;
cout<<"move"<<endl;
print(visit_flag);
}
}
cout<<"try end!!!"<<endl;
return i==len;
}
void print(vector<vector<int>>& board){
for(int i = 0;i < row;i++){
for(int j = 0;j < col;j++){
cout<<board[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
}
bool exist(vector<vector<char>>& board, string word) {
row = board.size();
col = board[0].size();
bool hasfind = false;
for(int i = 0;i < row && !hasfind;i++){
for(int j = 0;j < col && !hasfind;j++){
if(board[i][j] == word[0]){
hasfind = search(board, word, point(i, j, 0));
}
}
}
return hasfind;
}
};
感觉代码写的非常不优雅,可能采用递归会好一点。
加油!!