题目:
Given a 2D board and a word, find if the word exists in the grid.
The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.
For example,
Given board =
[ ["ABCE"], ["SFCS"], ["ADEE"] ]
word = "ABCCED"
,
-> returns true
,
word = "SEE"
,
-> returns true
,
word = "ABCB"
,
-> returns false
.
思路:我们首先分析问题,如何去找匹配的字符串,第一步先是从数组中找到匹配word第一个字符的位置,接下来就是在这个位置的四个方向(上下左右)递归搜索,看是否有匹配word的字符串,如果这些位置中的字母和word下一个字母相等,则从这些位置继续搜索。我们每次从一个元素出发时,对board中的元素已访问的标志可以设一个访问标志数组,也可以把已访问的元素设置为某个特殊字符,该题中设为”#“,如果搜索失败,我们需要恢复这个字母,虽然单次搜索字符不能重复,但是每次从一个新的元素出发,这个字符还是可以使用的。
Attention:
1. 为了节省搜索的时间成本,我们应该在递归前判断当前节点的上下左右节点是否符合条件(坐标条件,以及字符匹配条件),否何才进行进一步递归。
AC Code:
//上 if(i-1 >= 0 && board[i-1][j] == word[index+1]) if(exist_helper(board, word, i-1, j, index+1)) return true;
Error Code: 进入下一次递归,才进行判断,导致超时。
//如果i,j不在board范围内,并且不符合条件,则返回false if(i < 0 || i >= board.size() || j < 0 || j >= board[0].size() || used[i][j] || board[i][j] != word[index]) return false; used[i][j] = true; bool res; res = exist_helper(board, word, i-1, j, index+1, used) || exist_helper(board, word, i+1, j, index+1, used) || exist_helper(board, word, i, j-1, index+1, used) || exist_helper(board, word, i, j+1, index+1, used);
2. 这道题,字母不能重复使用,我们可以选择设置标志数组,或把字母设为特殊字符,这样可以保证无法匹配(如果再次搜索到这个字母),同时节省空间和时间,最后记得如果单次搜索失败(从一个字母出发),要恢复字母。我尝试了设置标志数组vector<vector<bool>>
used(row, vector<bool>(col, false)); 但也超时了,目前还不理解。
char ctmp = board[i][j]; board[i][j] = '#';
//匹配不成功,需要恢复原来的字母 board[i][j] = ctmp;
3. 由于我们每次先判断了四个方向的字母是否匹配word[index+1],匹配才进入下一层递归,所以迭代终止条件是如果index达到word.size()-1. 表明word字符都匹配成功,返回true. 如果选择index == word.size()终止, 当index = word.size()-1时,接下来调用word[index+1]会指针越界。
//如果word的所有字符都匹配成功,index到达word.size()-1,递归结束,返回true if(index == word.size()-1) return true;
4. 这道题设计很巧妙的地方,就是我们在主函数中遍历寻找匹配word第一个字母的位置,解下来从这个位置出发进行递归搜索,搜索成功,返回true. 递归函数只是在四个方向递归搜索,出发位置是在主函数中确定的。
for(int i = 0; i < row; i++) { for(int j = 0; j < col; j++) { if(board[i][j] == word[0] && exist_helper(board, word, i, j, 0)) return true; } } return false;
复杂度:最坏的情况,我们需要对每一个顶点都搜索一遍,总的时间复杂度O(M^2 * N^2)
AC Code:
class Solution { public: bool exist(vector<vector<char> > &board, string word) { if(word.size() == 0) return true; int row = board.size(); int col = board[0].size(); if(row == 0 || col == 0) return false; for(int i = 0; i < row; i++) { for(int j = 0; j < col; j++) { if(board[i][j] == word[0] && exist_helper(board, word, i, j, 0)) return true; } } return false; } private: bool exist_helper(vector<vector<char>> board, string word, int i, int j, int index) { //如果word的所有字符都匹配成功,index到达word.size()-1,递归结束,返回true if(index == word.size()-1) return true; char ctmp = board[i][j]; board[i][j] = '#'; //上 if(i-1 >= 0 && board[i-1][j] == word[index+1]) if(exist_helper(board, word, i-1, j, index+1)) return true; //下 if(i+1 < board.size() && board[i+1][j] == word[index+1]) if(exist_helper(board, word, i+1, j, index+1)) return true; //左 if(j-1 >= 0 && board[i][j-1] == word[index+1]) if(exist_helper(board, word, i, j-1, index+1)) return true; if(j+1 < board[0].size() && board[i][j+1] == word[index+1]) if(exist_helper(board, word, i, j+1, index+1)) return true; //匹配不成功,需要恢复原来的字母 board[i][j] = ctmp; return false; } };