文章目錄
- 題目
- 思路
- 注意
- 代碼
- 復雜度分析
題目
給定一個 m x 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
提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
board 和 word 僅由大小寫英文字母組成
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof
思路
深度優先搜索: 暴搜遍歷矩陣中所有字符串。DFS 通過遞歸,先朝一個方向搜到底,再回溯至上個節點,沿另一個方向搜索,以此類推。
剪枝: 在搜索中,遇到 這條路不可能和目標字符串匹配成功
的情況(例如:此矩陣元素和目標字符不同、此元素已被訪問),則應立即返回,稱之為 可行性剪枝
。
DFS細節:
- 遞推工作:
標記當前矩陣元素: 將 board[i][j] 修改為空字符 ''
,代表此元素已訪問過,防止之后搜索時重復訪問。 - 終止條件:
返回 false : (1) 行或列索引越界 或 (2) 當前矩陣元素與目標字符不同 或 (3) 當前矩陣元素已訪問過 ( (3) 可合并至 (2) ) 。
返回 true :k = word.size() - 1
,即字符串 word 已全部匹配。 - 搜索下一單元格:
朝當前元素的 上、下、左、右 四個方向開啟下層遞歸,使用或
連接 (代表只需找到一條可行路徑就直接返回,不再做后續 DFS ),并記錄結果至res
。 - 還原當前矩陣元素:
將 board[i][j] 元素還原至初始值,即 word[k] 。確保其他節點進行深搜時當前元素正常。 - 返回值:
返回布爾量res
,代表是否搜索到目標字符串。
注意
典型的深搜題目,值得一提的是,在寫代碼時,發現一個小小的改動就能帶來時間和空間的巨大優化,可能這就是編程語言的魅力吧(誤)。我們常說
拷貝傳值較之引用傳值:
- 引用傳值避免拷貝操作帶來的時間與空間的額外開銷。
- 拷貝傳值修改實參的拷貝而非實參本身,從而確保實參的安全性。
在構建dfs函數時,我們會修改board,但最終也會將其復原,因此調用board的安全性是可以保證的,也就意味著可以使用引用傳值。
而對于word,我們根本就不會去修改它,因此可以在聲明時為代表其的形參賦予const屬性,并以引用傳值的方式進行調用。
而對于i, j, k
,不將它們設置為引用傳參的原因是,在進行上、下、左、右四個方向的深搜時,要傳入一個表達式作為參數,而非常量引用必須綁定到左值,以i + 1
為例,表達式的結果作為臨時變量被綁定在臨時量const int& temp
上,而形參int& i
作為非常量引用
是無法綁定一個常量引用
綁定的對象的。
當
bool dfs(vector<vector<char>>& board, const string& word, size_t i, size_t j, int k);
時,時間、空間效率:
當
bool dfs(vector<vector<char>>& board, const string word, size_t i, size_t j, int k)
時,時間、空間效率:
該用引用的時候一定要用引用這句話深深刻在心里。。。。
代碼
class Solution {size_t rows, cols;bool dfs(vector<vector<char>>& board, const string& word, size_t i, size_t j, int k){if(i >= rows || i < 0 || j >= cols || j < 0 || board[i][j] != word[k]){return false;}if(k == (word.size() - 1)){return true;}board[i][j] = '\0';bool res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) ||dfs(board, word, i, j - 1, k + 1) || dfs(board, word, i, j + 1, k + 1);board[i][j] = word[k];return res;}
public:bool exist(vector<vector<char>>& board, string word) {rows = board.size();cols = board[0].size();for(size_t i = 0; i < rows; i++){for(size_t j = 0; j < cols; j++){bool falg = dfs(board, word, i, j, 0);if(falg){return true;}}}return false;}
};
復雜度分析
M, N 分別為矩陣行列大小, KK 為字符串 word 長度。
時間復雜度 O(MN3^K) :
- 最差情況下,需要遍歷矩陣中長度為 K 字符串的所有方案,時間復雜度為 O(3^K );矩陣中共有 MN 個起點,時間復雜度為 O(MN)。
- 方案數計算: 設字符串長度為 K ,搜索中每個字符有上、下、左、右四個方向可以選擇,舍棄回頭(上個字符)的方向,剩下 3 種選擇,因此方案數的復雜度為 O(3^K)。
- 空間復雜度 O(K): 搜索過程中的遞歸深度不超過 K ,因此系統因函數調用累計使用的棧空間占用 O(K) (因為函數返回后,系統調用的棧空間會釋放)。最壞情況下
K = MN
,遞歸深度為 MN ,此時系統棧使用 O(MN) 的額外空間。
作者:jyd
鏈接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof/solution/mian-shi-ti-12-ju-zhen-zhong-de-lu-jing-shen-du-yo/
來源:力扣(LeetCode)