?劍指 Offer 12. 矩陣中的路徑
難度:中等
給定一個 m * 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
提示:
m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board
和word
僅由大小寫英文字母組成
注意:本題 79. 單詞搜索 相同。
💡思路:回溯法
使用回溯法(backtracking)進行求解,它是一種暴力搜索方法,通過搜索所有可能的結果來求解問題。
回溯法在一次搜索結束時需要進行回溯(回退),將這一次搜索過程中設置的狀態進行清除,從而開始一次新的搜索過程。
例如下圖示例中,從 f
開始,下一步有 4 種搜索可能,
- 如果先搜索
b
,需要將b
標記為已經使用,防止重復使用。 - 在這一次搜索結束之后,需要將
b
的已經使用狀態清除,并搜索c
。
🍁代碼:(C++、Java)
C++
class Solution {
private:vector<pair<int, int>> dirs{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};int m, n;bool check(vector<vector<char>>& board, vector<vector<int>>& visited, int i, int j, string& s, int k){if(board[i][j] != s[k]) return false;if(k == s.size() - 1) return true;visited[i][j] = 1;bool ans = false;for(auto dir : dirs){int cur_i = i + dir.first, cur_j = j + dir.second;if(cur_i >= 0 && cur_i < m && cur_j >= 0 && cur_j < n && visited[cur_i][cur_j] == 0) {if(check(board, visited, cur_i, cur_j, s, k + 1)){ans = true;break;}}}visited[i][j] = 0;return ans;}
public:bool exist(vector<vector<char>>& board, string word) {m = board.size(); n = board[0].size(); vector<vector<int>> visited(m, vector<int>(n));for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){if(check(board, visited, i, j, word, 0))return true;}}return false;}
};
Java
class Solution {private int[][] dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private int m, n;private boolean check(char[][] board, int[][] visited, int i, int j, String s, int k){if(board[i][j] != s.charAt(k)) return false;if(k == s.length() - 1) return true;visited[i][j] = 1;boolean ans = false;for(int[] dir : dirs){int cur_i = i + dir[0], cur_j = j + dir[1];if(cur_i >= 0 && cur_i < m && cur_j >= 0 && cur_j < n && visited[cur_i][cur_j] == 0) {if(check(board, visited, cur_i, cur_j, s, k + 1)){ans = true;break;}}}visited[i][j] = 0;return ans;}public boolean exist(char[][] board, String word) {m = board.length; n = board[0].length; int[][] visited = new int[m][n];for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){if(check(board, visited, i, j, word, 0))return true;}}return false;}
}
🚀 運行結果:
🕔 復雜度分析:
- 時間復雜度:一個非常寬松的上界為 O ( m n ? 3 l ) O(mn*3^l) O(mn?3l),其中
m
,n
為網格的長度與寬度,l
為字符串word
的長度。在每次調用函數check
時,除了第一次可以進入 4 個分支以外,其余時間我們最多會進入 3 個分支(因為每個位置只能使用一次,所以走過來的分支沒法走回去)。 - 空間復雜度: O ( m n ) O(mn) O(mn)。我們額外開辟了 O ( m n ) O(mn) O(mn) 的
visited
數組,同時棧的深度最大為 O ( m i n ? ( l , m n ) ) O(min?(l, mn)) O(min?(l,mn))。。
題目來源:力扣。
放棄一件事很容易,每天能堅持一件事一定很酷,一起每日一題吧!
關注我LeetCode主頁 / CSDN—力扣專欄,每日更新!