?劍指 Offer 12. 矩陣中的路徑
難度:中等
給定一個(gè) m * n
二維字符網(wǎng)格 board
和一個(gè)字符串單詞 word
。如果 word
存在于網(wǎng)格中,返回 true
;否則,返回 false
。
單詞必須按照字母順序,通過(guò)相鄰的單元格內(nèi)的字母構(gòu)成,其中“相鄰”單元格是那些水平相鄰或垂直相鄰的單元格。同一個(gè)單元格內(nèi)的字母不允許被重復(fù)使用。
例如,在下面的 3×4 的矩陣中包含單詞 "ABCCED"
(單詞中的字母已標(biāo)出)。
示例 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)進(jìn)行求解,它是一種暴力搜索方法,通過(guò)搜索所有可能的結(jié)果來(lái)求解問(wèn)題。
回溯法在一次搜索結(jié)束時(shí)需要進(jìn)行回溯(回退),將這一次搜索過(guò)程中設(shè)置的狀態(tài)進(jìn)行清除,從而開始一次新的搜索過(guò)程。
例如下圖示例中,從 f
開始,下一步有 4 種搜索可能,
- 如果先搜索
b
,需要將b
標(biāo)記為已經(jīng)使用,防止重復(fù)使用。 - 在這一次搜索結(jié)束之后,需要將
b
的已經(jīng)使用狀態(tài)清除,并搜索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;
}
}
?? 運(yùn)行結(jié)果:
?? 復(fù)雜度分析:
-
時(shí)間復(fù)雜度:一個(gè)非常寬松的上界為
O
(
m
n
?
3
l
)
O(mn*3^l)
O(mn?3l),其中
m
,n
為網(wǎng)格的長(zhǎng)度與寬度,l
為字符串word
的長(zhǎng)度。在每次調(diào)用函數(shù)check
時(shí),除了第一次可以進(jìn)入 4 個(gè)分支以外,其余時(shí)間我們最多會(huì)進(jìn)入 3 個(gè)分支(因?yàn)槊總€(gè)位置只能使用一次,所以走過(guò)來(lái)的分支沒(méi)法走回去)。 -
空間復(fù)雜度:
O
(
m
n
)
O(mn)
O(mn)。我們額外開辟了
O
(
m
n
)
O(mn)
O(mn) 的
visited
數(shù)組,同時(shí)棧的深度最大為 O ( m i n ? ( l , m n ) ) O(min?(l, mn)) O(min?(l,mn))。。
題目來(lái)源:力扣。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-655632.html
放棄一件事很容易,每天能堅(jiān)持一件事一定很酷,一起每日一題吧!
關(guān)注我LeetCode主頁(yè) / CSDN—力扣專欄,每日更新!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-655632.html
注: 如有不足,歡迎指正!
到了這里,關(guān)于(搜索) 劍指 Offer 12. 矩陣中的路徑 ——【Leetcode每日一題】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!