题目描述
给定一个char[][] matrix,也就是char类型的二维数组,再给定一个字符串word,可以从任何一个某个位置出发,可以走上下左右,能不能找到word?
char[][] m =
{ { 'a', 'b', 'z' },
{ 'c', 'd', 'o' },
{ 'f', 'e', 'o' },
设定1:可以走重复路的情况下,返回能不能找到
比如,word = “zoooz”,是可以找到的,z -> o -> o -> o -> z,因为允许走一条路径中已经走过的字符
设定2:不可以走重复路的情况下,返回能不能找到
比如,word = “zoooz”,是不可以找到的,因为允许走一条路径中已经走过的字符不能重复走
题目解析
样本对应模型
暴力递归
定义 f ( i , j , k ) f(i,j,k) f(i,j,k)表示:从 i , j i,j i,j位置出发,能不能走出str从 k k k开头往后的所有字符
因为可以从任何一个位置出发,所以要对每一个位置都调用 f ( i , j , 0 ) f(i,j,0) f(i,j,0),只要有任何一个true,答案就是true
可以走重复路
// 从m[i][j]这个字符出发,能不能找到str[k...]这个后缀串
bool canLoop(std::vector<std::vector<char>> m, int i, int j, std::string str, int k){
//已经走完了
if(k == str.size()){
return true;
}
//还有字符需要走
//越界或者m[i][j] != str[k]
if(i == -1 || i == m.size() || j == -1 || j == m[0].size() || m[i][j] != str[k]){
return false;
}
// 不越界!m[i][j] == str[k] 对的上的!
// str[k+1....]
bool ans = false;
if (canLoop(m, i + 1, j, str, k + 1) || canLoop(m, i - 1, j, str, k + 1) || canLoop(m, i, j + 1, str, k + 1)
|| canLoop(m, i, j - 1, str, k + 1)) {
ans = true;
}
return ans;
}
不可以走重复路
关键在于怎么记住已经走过的路
// 从m[i][j]这个字符出发,能不能找到str[k...]这个后缀串
bool noLoop(std::vector<std::vector<char>> m, int i, int j, std::string str, int k){
//已经走完了
if(k == str.size()){
return true;
}
//还有字符需要走
//越界或者m[i][j] != str[k]
if(i == -1 || i == m.size() || j == -1 || j == m[0].size() || m[i][j] != str[k]
|| m[i][j] == 0){ //-----------回头路----------
return false;
}
// 不越界!m[i][j] == str[k] 对的上的
m[i][j] = 0;//标记本条路已经走过
// str[k+1....]
bool ans = false;
if (noLoop(m, i + 1, j, str, k + 1) || noLoop(m, i - 1, j, str, k + 1) || noLoop(m, i, j + 1, str, k + 1)
|| noLoop(m, i, j - 1, str, k + 1)) {
ans = true;
}
m[i][j] = str[k]; //恢复现场(******,以当前点作为起点的路已经尝试完毕了,一定要恢复,否则可能影响其他起点的选择)
return ans;
}
可以从任何一个位置出发
int ways(std::vector<std::vector<char>> &m, std::string &str){
if(str.empty()){
return 0;
}
int M = m.size(), N = m[0].size();
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
int p = xxxxx(i, j, 0, m, str);
if(p){
return true;
}
}
}
return false;
}
动态规划
不可以走重复路的不能改成动态规划,因为可变参数不只有i,j,k了,m参与到了可变参数中
bool checkPrevious(std::vector<std::vector<std::vector<bool>>> dp, int i, int j, int k) {
bool up = i > 0 ? (dp[i - 1][j][k - 1]) : false;
bool down = i < dp.size() - 1 ? (dp[i + 1][j][k - 1]) : false;
bool left = j > 0 ? (dp[i][j - 1][k - 1]) : false;
bool right = j < dp[0].size() - 1 ? (dp[i][j + 1][k - 1]) : false;
return up || down || left || right;
}
bool canLoop(std::vector<std::vector<char>> m, std::string w){
if(w.empty()){
return true;
}
if(m.empty() || m[0].empty()){
return false;
}
int N = m.size(), M = m[0].size(), len = w.size();
// dp[i][j][k]表示:必须以m[i][j]这个字符结尾的情况下,能不能找到w[0...k]这个前缀串
std::vector<std::vector<std::vector<bool>>> dp(N, std::vector<std::vector<bool>>(M, std::vector<bool>(len, false)));
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
dp[i][j][0] = (m[i][j] == w[0]);
}
}
for (int k = 1; k < len; k++) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
dp[i][j][k] = (m[i][j] == w[k] && checkPrevious(dp, i, j, k));
}
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (dp[i][j][len - 1]) {
return true;
}
}
}
return false;
}
类似题目
题目 | 思路 |
---|---|
leetcode:79. 二维矩阵可以走出的单词(可以重复路,不可以重复路)Word Search | 回溯,动态规划(不可以走重复路不能改动态规划) |
leetcode:212. 二维矩阵可以走出的哪些单词(不可以重复路)Word Search II II | 回溯 + 字典树 |
leetcode:208. 实现字典树(前缀树) Implement Trie (Prefix Tree) | |
leetcode:211. 添加与搜索单词 - 数据结构设计 | . 可以匹配任何一个单词,所以有了. 就要搜索26条子路 |
leetcode:980. 不同路径 III Unique Paths III | 回溯 |
1032. 字符流 Stream of Characters |