劍指Offer12|LeetCode79.矩陣中的路徑
阿新 • • 發佈:2021-08-02
題目
給定一個m x n 二維字元網格board 和一個字串單詞word 。如果word 存在於網格中,返回 true ;否則,返回 false 。
單詞必須按照字母順序,通過相鄰的單元格內的字母構成,其中“相鄰”單元格是那些水平相鄰或垂直相鄰的單元格。同一個單元格內的字母不允許被重複使用。
示例 1:
輸入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
輸出:true
示例 2:
輸入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE" 輸出:true
示例 3:
輸入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
輸出:false
提示:
m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board 和 word 僅由大小寫英文字母組成
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/word-search
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。
解題方法
DFS回溯
1.雙重迴圈找到字串的起點
2.基於起點上下左右四個方向找剩餘路徑
3.在找的過程中判斷選擇是否正確,是否越界,是否已訪問過
4.宣告一個變數儲存訪問過的元素
5.如果遞迴下一個節點時錯誤的,說明當前選擇也是錯誤的,需要把當前元素的是否訪問狀態改回未訪問
時間複雜度O(MN*3^L) M,N為網格的長寬 L為字串長度 每次遞迴除了第一次可以進入4個分支,
其餘最多進入3個分支,因為每個位置只能一次,走過無法再訪問。
空間複雜度O(MN) 開闢儲存是否訪問過的陣列
如果採用修改原陣列的方法 空間複雜度O(1)
程式碼
// dfs + 輔助陣列 func exist(board [][]byte, word string) bool { m,n := len(board),len(board[0]) // 訪問記錄 visited := make([][]bool,m) for i := 0;i < m;i++{ visited[i] = make([]bool,n) } var canFind func(r,c,i int) bool canFind = func(r, c, i int) bool { // 已經找到複合字符串長度的路徑 if i == len(word){ return true } // 索引越界 if r < 0 || r >= m || c < 0 || c >= n{ return false } // 當前元素已訪問過或者當前元素不等於當前需要找的字元 if visited[r][c] || board[r][c] != word[i] { return false } // 設定當前元素為已訪問狀態 visited[r][c] = true // 遞迴剩餘路徑 在 || 判斷中,只要有符合的便不會繼續執行後面的判斷,達到剪枝的目的 if canFind(r+1,c,i+1) || canFind(r-1,c,i+1) || canFind(r,c+1,i+1) || canFind(r,c-1,i+1){ return true } // 沒有符合的路徑 將當前元素訪問狀態回退 visited[r][c] = false return false } for i := 0;i < m;i++ { for j := 0;j < n;j++{ if board[i][j] == word[0] && canFind(i,j,0){ return true } } } return false } // dfs + 直接修改原陣列 func exist2(board [][]byte, word string) bool { m,n := len(board),len(board[0]) var canFind func(r,c,i int) bool canFind = func(r, c, i int) bool { // 已經找到複合字符串長度的路徑 if i == len(word){ return true } // 索引越界 if r < 0 || r >= m || c < 0 || c >= n{ return false } // 如果當前元素不等於尋找元素 if board[r][c] != word[i] { return false } // 修改元素,表示已訪問 temp := board[r][c] board[r][c] = ' ' // 遞迴剩餘路徑 在 || 判斷中,只要有符合的便不會繼續執行後面的判斷,達到剪枝的目的 if canFind(r+1,c,i+1) || canFind(r-1,c,i+1) || canFind(r,c+1,i+1) || canFind(r,c-1,i+1){ return true } // 沒有符合的路徑 將當前元素回退 board[r][c] = temp return false } for i := 0;i < m;i++ { for j := 0;j < n;j++{ if board[i][j] == word[0] && canFind(i,j,0){ return true } } } return false }