字符串路径问题
1:题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2:题目分析
递归算法的核心:有以下三点
- 明确递归终止条件;即在进行再次递归之前,判断是否到依然满足条件,是否达到目的地。
- 明确在终止条件下的操作,是返回代表已经解决问题,还是本次递归不满足,需要回溯回去。
- 明确重复步骤,即重复解决问题的代码;所以递归问题中,都是要利用重复逻辑来解决问题的,所以这个部分是关键!
针对本题目,我们设计的递归算法的思路如下:
首先,遍历二维数组,在满足该位置字符与word第一个字符匹配的条件下,在进行递归算法的处理。
递归算法的设计如下;
- 判断该位置是否与字符串位置匹配,若匹配则进行下面步骤,否则返回false,该子路递归终止,进行回溯。
- 在判断该位置的四周位置的字符是否与字符串下一个位置字符匹配,按照上下左右的顺序进行判断。逻辑依然与本递归算法一样,即先本位置,再周围,一旦不满足就return false,若满足则不断递归下去,直到满足终止条件,return true,开始回溯。
3:代码说话
class Solution { private int times = 0; private int[][] arr = null; public boolean exist(char[][] board, String word) { arr = new int[board.length][board[0].length]; //从当前二维数组的每一个位置当当作起点,进行尝试寻找路径。 for(int i=0;i<board.length;i++){ for(int j=0;j<board[0].length;j++){ //当第一个字符满足时,才进行判断。 if(board[i][j] == word.charAt(0)) { if (fit(board, i, j, word)) { return true; } } } } return false; } //以当前位置为起点,通过递归判断四周,一直递归直到找到目标路径。做好回溯的处理(变量的复原) public boolean fit(char[][] board,int i,int j,String word){ //i和j必须满足范围 //满足条件 if(i>=board.length||i<0||j>=board[0].length||j<0){ return false; } //如果word所有字符都匹配了,则返回true //成功的终止条件 if(times == word.length()){ //直接返回true,即可! return true; } else{ //当前位置和字符串字符一致,则递归判断其周围的字符是不符合要求, //同时再另外一个与之对应的二维数组里记录是该位置字符是否已经参与匹配了! if(board[i][j] == word.charAt(times)){ times++; //假如当前位置已经是最后一个正确的位置了,则直接返回true, if(times == word.length()){ return true; } //若该位置暂时匹配,则至1,意味着该位置字符已经被匹配过了。 //同时再下面的向四周判断中,如果发现当前位置arr[i][j]=1,则不再进行判断 arr[i][j] = 1; //在判断上面字符,且上字符没有匹配过 if(i>0&&arr[i-1][j]==0&&fit(board,i-1,j,word)){ return true; } else{ //在判断右面字符,且右字符没有匹配过 if(j<(board[0].length-1)&&arr[i][j+1]==0&&fit(board,i,j+1,word)){ return true; } else { //在判断下面字符,且下字符没有匹配过 if(i<(board.length-1)&&arr[i+1][j]==0&&fit(board,i+1,j,word)){ return true; } else{ //在判断左面字符,且左字符没有匹配过 if(j>0&&arr[i][j-1]==0&&fit(board,i,j-1,word)){ return true; } //如果当前位置的4个方向所有字符都不满足要求,则返回false。 //同时,上次进入本位置的选择是错误的所有times-- else{ //如果只是当前位置字符满足匹配,其四周不满足匹配, //则意味着,当前路径不对 //则times--,同时撤回前面对应位置的至1,操作 arr[i][j] = 0; times--; return false; } } } } } else{ //当前位置字符不满足, return false; } } } }