给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
例如,在上面的 3×4 的矩阵中包含单词 "ABCCED"(单词中的字母已标出)。
示例 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
board 和 word 仅由大小写英文字母组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
考点:
深度优先搜索+剪枝
主要思路:
- **起始位置。**由于起始位置并不确定,因此需要通过遍历矩阵,挨个查找。而后针对每个起始点,使用深度优先搜索来查找字符串。
- **深度优先搜索。**对于每个起始点,使用深度优先搜索。深度优先搜索是,只要满足条件就一直往下走,先走通一条路。当遇到不满足条件的就回溯,站在上一个节点位置(有多个路口可以走,如A\B\C),转向走下一个路口B,如路口B还不满足,就走路口C。
- **约束条件。**在确定某个节点是否满足的条件是,如果 走过的路 或者 走到了边界 或者 字符不对应,那么就不能选择这个节点,因此返回false;如果走过的节点索引k等于word.size()-1,那么就说明找到了,返回true。
- **递归实现。**由于只需要找到一条路就可以,因此针对当前节点的多个选择,只要有一个路径选择正确(返回true)即可,因此多个递归调用的关系是 或|| 的关系。
- **时间复杂度。**时间复杂度为O(3^k MN)。每个字符需要判断3次,总共k个字符,而需要参与判断的起始点有MN个。
- **空间复杂度。**空间复杂度为O(k)。递归操作最多需要入栈k次。
下图以及代码来源:
面试题12. 矩阵中的路径( DFS + 剪枝 ,清晰图解)
代码:
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
row = board.size()-1;
col = board[0].size()-1;
int k=0;
for(int i=0; i<=row; ++i){
for(int j=0; j<=col; ++j){//每个点作为起始点
if(findchar(board, word, i, j, k)) return true;//如果当前点作为起始点满足条件,那么就返回true
}
}
return false; //Line 12: Char 5: error: non-void function does not return a value in all control paths 每个途径都要返回bool
}
private:
int row, col;
bool findchar(vector<vector<char>>&board, string& word, int i, int j, int k){//针对每个起始点进行搜索
if(i>row || j>col ||i<0 || j<0 || board[i][j]!=word[k]) return false;//如果越界,或者当前节点不等于word中第k个字符,则不满足条件;
//如果当前节点等于word中第k个字符,那么再看是否所有字符查找完毕
if(k==word.size()-1) return true;//所有字符查找完毕就返回true
board[i][j] = '\0'; //如果没有查找完毕,并且当前字符找的正确,那么就标记为空字符,后边就不能重复这个字符了
bool res = findchar(board, word, i-1, j, k+1) || findchar(board, word, i+1, j, k+1)||//进行上下左右查找,只要有一个满足条件就可以返回true
findchar(board, word, i, j-1, k+1) || findchar(board, word, i, j+1, k+1);
board[i][j] = word[k];//恢复这个字符,因为以后可能有别的起始点查找,这个过程是回溯的过程。在每层递归下都会恢复。
return res;
}
};
出现问题:
数组越界问题:计算row以及col,和判断越界的代码不相符导致数组越界。
/*
AddressSanitizer:DEADLYSIGNAL
=================================================================
==42==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x00000034c6d7 bp 0x7ffd9ede0200 sp 0x7ffd9ede01a0 T0)//数组越界
==42==The signal is caused by a READ memory access.
==42==Hint: this fault was caused by a dereference of a high value address (see register values below). Dissassemble the provided pc to learn which register was used.
#9 0x7f7ccbee70b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
AddressSanitizer can not provide additional info.
==42==ABORTING
*/