1. 程式人生 > >Leetcode 79. Word Search (詞搜尋)

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:

  • 這道題花費了大量的時間精力,其中出現的錯誤有三點:
  1. 對走過的座標點進行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:來判斷是否已經走過該座標點了。

  2. 錯誤地進行了開始以為應該是用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)
  3. 判定成立條件必須首先回溯程式的起始位置,不然程式依舊會報錯,原因是得到成立結果的同時,可能也已經遍歷完所有的matrix元素,此時,跳出回溯的不成立條件也達到了,如if row < 0 or row >= len(board) or col < 0 or col >= len(board[0]):也是成立,若是將其放在回溯程式起始位置,則最終會返回一個False
  4. 對於這種從任意起點開始判定是否存在路徑的方法,不如將迴圈主體放在呼叫回溯程式的主程式中,因為此時,只需有一個滿足即可進行範圍,有利於程式的提前終止,本題就是採用了將兩個for迴圈放在了主程式中,遍歷每個元素並進行回溯。
  5. 事實上,這道題有個bug,在輸入為[["a, a"]], "a, a, a"時,自己寫的程式在本機跑的結果與提交程式跑出來的結果不同,因此,本部落格也將能通過稽核的答案放在了參考答案中。

參考資料

[1] https://blog.csdn.net/fuxuemingzhu/article/details/79386066