Leetcode 79. Word Search (詞搜尋)
原題
Given a 2D board and a word, find if the word exists in the grid.
The word can be constructed from letters of sequentially adjacent cell, where “adjacent” cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.
Example:
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.
Reference Answer
思路分析
還是經典的回溯法問題。這個題的回溯的起點可以是二維陣列的任意位置。
回溯法的判定條件比較簡單,需要注意的是把已經走過的路給改變了,不能再走了。python中通過swapcase()交換該字母的大小寫即可行。
My Code(有bug,本機跑結果與提交結果不同)
class Solution:
def exist(self, board, word):
"""
:type board: List[List[str]]
:type word: str
:rtype: bool
"""
if not board and word:
return False
elif board and not word:
return True
elif not board and not word:
return True
# rows, cols = len(board), len(board[0])
mark = []
for x in range(len(board)):
for y in range (len(board[0])):
if self.helper(x, y, 0, board, word, mark):
return True
return False
def helper(self, row, col, word_index, board, word, mark):
if word_index == len(word):
return True
if row < 0 or row >= len(board) or col < 0 or col >= len(board[0]):
return False
if board[row][col] != word[word_index]:
return False
if board[row][col] in mark:
return False
return self.helper(row + 1, col, word_index + 1, board, word, mark + [[row, col]]) or \
self.helper(row - 1, col, word_index + 1, board, word, mark + [[row, col]]) or \
self.helper(row, col + 1, word_index + 1, board, word, mark + [[row, col]]) or \
self.helper(row, col - 1, word_index + 1, board, word, mark + [[row, col]])
Reference Code
class Solution(object):
def exist(self, board, word):
"""
:type board: List[List[str]]
:type word: str
:rtype: bool
"""
for y in xrange(len(board)):
for x in xrange(len(board[0])):
if self.exit(board, word, x, y, 0):
return True
return False
def exit(self, board, word, x, y, i):
if i == len(word):
return True
if x < 0 or x >= len(board[0]) or y < 0 or y >= len(board):
return False
if board[y][x] != word[i]:
return False
board[y][x] = board[y][x].swapcase()
isexit = self.exit(board, word, x + 1, y, i + 1) or self.exit(board, word, x, y + 1, i + 1) or self.exit(board, word, x - 1, y, i + 1) or self.exit(board, word, x, y - 1, i + 1)
board[y][x] = board[y][x].swapcase()
return isexit
Note:
- 這道題花費了大量的時間精力,其中出現的錯誤有三點:
- 對走過的座標點進行mark的標記方式不對,本來想利用回溯法的優勢,直接在return中完成走過點座標位置的新增,事實上新增方式不對:
錯誤方式:
mark + [col, row]
,事實證明這種程式設計方式的結果為[row_1,col_1,row_2,col_2...]
,不是想要的[[row_1, col_2], [row_2, col_2]...]
,因此,在這種方式下,想通過if board[row][col] in mark:
來判斷是否已經走過該座標點,本身就不證明,這種判斷方式永遠不成立(如 [1,2] not in [1,2,3,4]恆成立);
若想通過該方式進行判定,需要用mark + [[col, row]]
,這樣,標記的座標點為[[row_1, col_1], [row_2, col_2]. [row_3, col_3]...]
,就可以進行if board[row][col] in mark:
來判斷是否已經走過該座標點了。 - 錯誤地進行了開始以為應該是用
if word_index == len(word)-1:
來作為判定成功的標誌,事實上,應該是用if word_index == len(word):
,因為該判定語句是放在第一個判定條件的(事實證明,該成功判定條件必須放在首位置,詳見第3條),此時,還沒有進行索引指定內容的判別,如if board[row][col] != word[word_index]
等,因此,成立條件是在判定完所有0:len(word)-1
所有內容後,此時word_index == len(word)
。 - 判定成立條件必須首先回溯程式的起始位置,不然程式依舊會報錯,原因是得到成立結果的同時,可能也已經遍歷完所有的matrix元素,此時,跳出回溯的不成立條件也達到了,如
if row < 0 or row >= len(board) or col < 0 or col >= len(board[0]):
也是成立,若是將其放在回溯程式起始位置,則最終會返回一個False
; - 對於這種從任意起點開始判定是否存在路徑的方法,不如將迴圈主體放在呼叫回溯程式的主程式中,因為此時,只需有一個滿足即可進行範圍,有利於程式的提前終止,本題就是採用了將兩個for迴圈放在了主程式中,遍歷每個元素並進行回溯。
- 事實上,這道題有個bug,在輸入為
[["a, a"]], "a, a, a"
時,自己寫的程式在本機跑的結果與提交程式跑出來的結果不同,因此,本部落格也將能通過稽核的答案放在了參考答案中。
參考資料
[1] https://blog.csdn.net/fuxuemingzhu/article/details/79386066