给定一个字符矩阵,以及一个字符串,求字符矩阵能否组成字符串,字符组建规则:当前字符上下左右都可以组建成字符串,一个位置的字符只能组建一次。
board =
[
[‘A‘,‘B‘,‘C‘,‘E‘],
[‘S‘,‘F‘,‘C‘,‘S‘],
[‘A‘,‘D‘,‘E‘,‘E‘]
]
Given word = "ABCCED", return true.
Given word = "SEE", return true.
Given word = "ABCB", return false.
思路:
使用DFS来查找答案,每一次递归调用,分别遍历当前字符上下左右4个位置的字符,而对于怎么判断组建的字符串到多少位了,用 n 来记录即可,n表示遍历到给定字符串 word的多少位了,当 n == word.size( ) ,说明已经将字符串word遍历完了,因为当矩阵字符与字符串对 应下标字符不相等时,就跳出当前递归,返回false了,而 n == word.size( ),表示前面的字符都与字符串word相等,即表示找到答案了,返回true。防止将一个字符多次使用,即防止走回头路,需要将已经遍历的字符修改成 ‘0‘,当4个位置都遍历完时,再将原来的值恢复,既得到了答案,又没有修改矩阵,还不引入额外的空间,一举三得。
class Solution { public: bool exist(vector<vector<char>>& board, string word) { if (board.empty() || board[0].empty()) return false; int row = board.size(), col = board[0].size(); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { if (board[i][j] != word[0]) continue;//当首字母相等时才递归判断,否则跳过。减少不必要的递归调用开销 if (existDFS(board, word, 0, i, j)) return true; } } return false; } bool existDFS(vector<vector<char>>& board, string& word, int n, int i, int j) { if (n == word.size()) return true; if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size() || board[i][j] != word[n]) return false; char c = board[i][j]; board[i][j] = ‘0‘; bool res = (existDFS(board, word, n + 1, i, j - 1) || existDFS(board, word, n + 1, i, j + 1) || existDFS(board, word, n + 1, i - 1, j) || existDFS(board, word, n + 1, i + 1, j)); board[i][j] = c; return res; } };
注意的点:
不要将4个位置都遍历完了,最后再一起判断,如下:
bool res1 = existDFS(board, word, n + 1, i, j - 1);
bool res2 = existDFS(board, word, n + 1, i, j + 1);
bool res3 = existDFS(board, word, n + 1, i - 1, j);
bool res4 = existDFS(board, word, n + 1, i + 1, j);
board[i][j] = c;
return (res1 || res2 || res3 || res4);
因为这样必须将4个位置都遍历完,当矩阵特别大,字符串特别大时,就算 res1 找到了答案,也还需要耗费大量时间去遍历 res2, res3, res4. 最终导致超时,OJ不AC。
使用“或”运算,只要找到一个答案为真,则不再继续找另外的位置了。
原文:https://www.cnblogs.com/luo-c/p/13028556.html