leetcode刷题日记2020-10-03

153 阅读3分钟

主要内容

  1. DFS
  2. backtracking
  3. BFS: 两种BFS遍历方式

括号生成

leetcode-cn.com/problems/ge…

思路

DFS + backtracing 代码基本上是模板化的,只需要注意剪枝条件和递归终止条件

代码

class Solution:
    # def generateParenthesis(self, n: int) -> List[str]:
    def generateParenthesis(self, n):
        """
        dfs + backtracking
        :param n:
        :return:
        """
        result = []
        def dfs(path, left_num, right_num):
            if left_num + right_num == 2 * n:
                if left_num == n:
                    result.append("".join(path))
                return
            if left_num < n:
                dfs(path + ["("], left_num + 1, right_num)
            if right_num < left_num:
                dfs(path + [")"], left_num, right_num + 1)
            return

        dfs([], 0, 0)
        return result

在每个树行中找最大值

leetcode-cn.com/problems/fi…

思路

BFS,分层保存数据

代码

class Solution:
    # def largestValues(self, root: TreeNode) -> List[int]:
    def largestValues(self, root):
        """
        BFS, 按照层数更新最大值
        :param root:
        :return:
        """
        result = []
        queue = [(0, root)]
        while len(queue) > 0:
            depth, node = queue.pop(0)
            if node is None:
                continue
            while depth >= len(result):
                result.append(-float("inf"))
            result[depth] = max(node.val, result[depth])
            queue.append((depth+1, node.left))
            queue.append((depth+1, node.right))

        return result

单词接龙

leetcode-cn.com/problems/wo…

思路

思路一

本题思路非常简单:由于是搜索最短路径,所以在BFS和DFS中必然使用BFS算法。主要问题在于BFS中的剪枝策略优化,如果不额外进行剪枝优化,大概率会出现超时问题:

  1. 使用通配符,例如"d*g"来匹配所有首字母和尾字幕分别为d和g的单词,减少遍历量级
  2. 及时清理需要遍历的分支,将不需要遍历的分支清除(本题中需要及时清除字典中对应key的value)

思路二

参考自 leetcode.com/problems/wo…

由于后续第二题要求重建路径,而思路一中的剪枝过程会导致路径回溯出现异常,因此需要考虑新的BFS方案:逐层扫描,生成对应层的数据

代码

代码一

        word_set = set(wordList)
        if endWord not in word_set or not endWord or not beginWord or not word_set:
            return 0
        word_dict = dict()
        for word in wordList:
            for i in range(len(word)):
                key = word[:i] + "*" + word[i+1:]
                if key in word_dict:
                    word_dict[key].append(word)
                else:
                    word_dict[key] = [word]
        queue = [(1, beginWord)]
        while queue:
            num, word = queue.pop(0)
            if word == endWord:
                return num
            if word in word_set:
                word_set.remove(word)
            for i in range(len(word)):
                key = word[:i] + "*" + word[i+1:]
                if key not in word_dict:
                    continue
                for new_word in word_dict[key]:
                    if new_word not in word_set:
                        continue
                    else:
                        queue.append((num+1, new_word))
                word_dict[key] = []
        return 0

代码二

class Solution:
    # def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
    def ladderLength(self, beginWord, endWord, wordList):
        """
        BFS
        剪枝
        :param beginWord:
        :param endWord:
        :param wordList:
        :return:
        """
        # 另一种bfs实现逻辑
        # https://leetcode.com/problems/word-ladder/discuss/352659/Simple-Python-BFS-solution
        word_set = set(wordList)
        if endWord not in word_set:
            return 0
        layer = {beginWord}
        dist = 1
        while len(layer) > 0:
            word_set -= layer
            next_layer = set()
            for word in layer:
                for i in range(len(word)):
                    for ch in "abcdefghijklmnopqrstuvwxyz":
                        new_word = word[:i] + ch + word[i+1:]
                        if new_word == endWord:
                            return dist+1
                        if new_word not in word_set:
                            continue
                        else:
                            next_layer.add(new_word)
            layer = next_layer
            dist += 1
        return 0

单词接龙 II

leetcode-cn.com/problems/wo…

思路

参考:leetcode.com/problems/wo…

衔接上一题的思路二,采用字典存储从子节点到父节点的所有路径,用于后续的路径重建

代码

class Solution:
    # def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
    def findLadders(self, beginWord, endWord, wordList):
        """
        BFS
        :param beginWord:
        :param endWord:
        :param wordList:
        :return:
        """
        word_set = set(wordList)
        layer = {beginWord}
        parents = dict()
        while len(layer) > 0:
            word_set -= layer
            next_layer = set()
            for word in layer:
                for i in range(len(word)):
                    for ch in "abcdefghijklmnopqrstuvwxyz":
                        new_word = word[:i] + ch + word[i + 1:]
                        if new_word not in word_set:
                            continue
                        next_layer.add(new_word)
                        if new_word not in parents:
                            parents[new_word] = [word]
                        else:
                            parents[new_word].append(word)
            if endWord in next_layer:
                break
            layer = next_layer

        result = []
        def dfs(path):
            if path[-1] == beginWord:
                result.append(path[::-1])
                return
            last_word = path[-1]
            if last_word not in parents:
                return
            for word in parents[last_word]:
                dfs(path + [word])

        dfs([endWord])
        return result

岛屿数量

leetcode-cn.com/problems/nu…

思路

DFS遍历所有能触达的陆地,然后标记为0,统计最外层遍历过陆地的次数

代码

class Solution(object):
    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        height = len(grid)
        if height == 0:
            return 0
        width = len(grid[0])
        if width == 0:
            return 0

        def dfs(row, col):
            if grid[row][col] == '0':
                return
            grid[row][col] = '0'

            for (i, j) in [(row-1, col), (row+1, col), (row, col-1), (row, col+1)]:
                if i < 0 or i >= height:
                    continue
                if j < 0 or j >= width:
                    continue
                dfs(i, j)

        num_islands = 0
        for i in range(height):
            for j in range(width):
                if grid[i][j] == '1':
                    num_islands += 1
                dfs(i, j)
        return num_islands