1. 程式人生 > >DFS+回溯專題14 - leetcode756. Pyramid Transition Matrix/79. Word Search - Medium

DFS+回溯專題14 - leetcode756. Pyramid Transition Matrix/79. Word Search - Medium

756. Pyramid Transition Matrix

題目描述

給定一個bottom字串,和allowed陣列。
allowed陣列中每一個字串都含有一個三元組(A,B,C),表示一種規則:C的左孩子可以是A,右孩子可以是B。

判斷給定bottom和allowed,是否能構造一個金字塔的結構,滿足allowed的規則,並且金字塔的最後一層就是bottom字串。

例子

Example 1:
Input: bottom = “XYZ”, allowed = [“XYD”, “YZE”, “DEA”, “FFF”]
Output: true
可以形成如下所示的金字塔:
  A
 /  \
 D   E
 / \  / \
X Y   Z

Example 2:
Input: bottom = “XXYX”, allowed = [“XXX”, “XXY”, “XYX”, “XYY”, “YXZ”]
Output: false

注意:可以存在三元組 (A, B, C) 和 (A, B, D),其中 C != D.

思想
在當前bottom的基礎上,遞推上一層的結點,直到結點只包含1個 → 構造完成。
1)遞推上一層:建一個 dic 拆分三元組,例如(X,Y,Z),則記錄dic[(X,Y)] = [z];
2)allLists 儲存上一層可能包含的結點。例如[[‘X’,‘Y’], [‘Z’]],表示上一層可能為’XZ’或’YZ’;
3)helper

函式用來組合,在 allLists 基礎上構造上一層可能的狀態。例如[[‘X’,‘Y’], [‘Z’]] → [‘XZ’, ‘YZ’],(其中combs = [‘XZ’, ‘YZ’]表示上一層可能的狀態);
4)省時間,cache 儲存已判斷過的bottom,記錄以該bottom為底,是否可構造金字塔。例如在遞迴過程中,'XZZ’可以構造金字塔,則 cache[‘XZZ’] = True,下次再遇到’XZZ’就無需判斷了~

解法
全組合採用BFS,而不是DFS。

class Solution(object):
    def pyramidTransition(self, bottom,
allowed): """ :type bottom: str :type allowed: List[str] :rtype: bool """ self.dic = {} self.cache = {} allowed = set(allowed) for allow in allowed: if allow[:2] not in self.dic: self.dic[allow[:2]] = [allow[-1]] else: self.dic[allow[:2]].append(allow[-1]) return self.dfs(bottom) def dfs(self, bottom): if len(bottom) == 2: return bottom in self.dic if bottom in self.cache: return self.cache[bottom] allLists = [] for i in range(len(bottom)-1): if bottom[i:i+2] not in self.dic: self.cache[bottom] = False return False allLists.append(self.dic[bottom[i:i+2]]) combs = self.helper(allLists) for comb in combs: if self.dfs(comb): self.cache[comb] = True return True self.cache[bottom] = False return False def helper(self, allLists): queue = [''] for List in allLists: for _ in range(len(queue)): node = queue.pop(0) for c in List: queue.append(node + c) return queue

原始:全組合採用的DFS,TLE

class Solution(object):
    def pyramidTransition(self, bottom, allowed):
        """
        :type bottom: str
        :type allowed: List[str]
        :rtype: bool
        """
        self.dic = {}
        self.cache = {}
        for allow in allowed:
            if allow[:2] not in self.dic:
                self.dic[allow[:2]] = [allow[2]]
            else:
                self.dic[allow[:2]] += [allow[2]]
                
        return self.dfs(bottom)
                
    def dfs(self, bottom):
        if len(bottom) == 1:
            return True
        if bottom in self.cache:
            return self.cache[bottom]
        
        allLists = []
        for i in range(len(bottom)-1):
            if bottom[i:i+2] not in self.dic:
                self.cache[bottom] = False
                return False
            allLists.append(self.dic[bottom[i:i+2]])
        
        combs = []
        self.helper(allLists, '', combs)
        
        for comb in combs:
            if self.dfs(comb):
                self.cache[comb] = True
                return True
            
        self.cache[bottom] = False
        return False  
        
    def helper(self, allLists, temp, combs):
        if not allLists:
            combs.append(temp)
            return
        for List in allLists:
            for c in List:
                self.helper(allLists[1:], temp + c, combs)

79. Word Search

題目描述

給定一個2D網格和一個單詞word,判斷word是否存在於網格中。

單詞可以由順序相鄰的單元字母重構(水平相鄰和垂直相鄰),用過的單元不能重複使用。

例子

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.

思想
比較經典的路徑搜尋回溯。
1)首先,主體函式的兩層for迴圈 → 確定路徑的起點;
2)DFS中
截止條件:已遍歷完word;
主體部分:當前位置是否有效(0 <= x < m and 0 <= y < n),且未被訪問過(not visited[x][y]),且和word匹配(board[x][y] == word[0])?是的話,搜尋上、下、左、右4個位置。其中visited是標記該位置是否被訪問過。

解法

class Solution(object):
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        m, n = len(board), len(board[0])
        visited = [[False] * n for _ in range(m)]
        for x in range(m):
            for y in range(n):
                if self.dfs(board, word, m, n, x, y, visited):
                    return True
        return False
                    
    def dfs(self, board, word, m, n, x, y, visited):
        if not word:
            return True
        if 0 <= x < m and 0 <= y < n and not visited[x][y] and board[x][y] == word[0]:
            visited[x][y] = True
            if (self.dfs(board, word[1:], m, n, x+1, y, visited) 
                or self.dfs(board, word[1:], m, n, x-1, y, visited) 
                or self.dfs(board, word[1:], m, n, x, y+1, visited) 
                or self.dfs(board, word[1:], m, n, x, y-1, visited)):
                return True
            visited[x][y] = False
        return False