Leetcode题解 - BFS部分题目代码+思路(896、690、111、559、993、102、103、127、433)

和树有关的题目求深度 -> 可以利用层序遍历 -> 用到层序遍历就想到使用BFS


896. 单调数列 - 水题

class Solution:
    def isMonotonic(self, A) -> bool:
        if sorted(A) == A or sorted(A, reverse=True) == A:
            return True
        return False

690. 员工的重要性 - 简单BFS

class Solution:
    def getImportance(self, employees, id):
        """
        :type employees: Employee
        :type id: int
        :rtype: int
        """
        s = 0
        Q = []
        for i in employees:
                if i.id == id:
                    Q.append(i)
        while len(Q) != 0:
            boss = Q.pop(0)
            importance = boss.importance
            subordinate = boss.subordinates
            s += importance
            for i in employees:
                if i.id in subordinate:
                    Q.append(i)
        return s

# e1 = Employee(1, 5, [2, 3])
# e2 = Employee(2, 3, [])
# e3 = Employee(3, 3, [])
# Employ = [e1, e2, e3]
# print(Solution().getImportance(Employ, 1))

111. 二叉树的最小深度 - 简单BFS

"""
BFS就是对树的层序遍历,发现的第一个叶子节点一定是深度最小的
"""
class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if root == None:
            return 0
        Q = [(root, 1)]
        while len(Q) != 0:
            node, deepth = Q.pop(0)
            if node.left == None and node.right == None:
                return deepth
            if node.left:
                Q.append((node.left, deepth+1))
            if node.right:
                Q.append((node.right, deepth+1))

559. N叉树的最大深度 - 和楼上找最小深度思路一样

在这里插入图片描述

"""
BFS结束后肯定是到了这个树的最后一层,设置一个层数标志位,不断更新标志位,则BFS退出后标志位的值就是最后一层的层数。
"""
class Solution:
    def maxDepth(self, root) -> int:
        if root == None:
            return 0
        Q = [(root, 1)]
        m = 0
        while len(Q) != 0:
            node, deepth = Q.pop(0)
            m = deepth
            for i in node.children:
                Q.append((i, deepth+1))
        return m 

993. 二叉树的堂兄弟节点

"""
BFS - 记录每个节点的深度和父节点,再去比较题目中给定的x和y的深度与父节点
"""
class Solution:
    def isCousins(self, root: TreeNode, x: int, y: int) -> bool:
        if root == None:
            return False
        # 节点,层数,父节点
        Q = [(root, 1, None)]
        checkOver = 0
        d = []
        par = []
        while len(Q) != 0:
            node, depth, parent = Q.pop(0)
            if node == None:
                break
            if node.val == x or node.val == y:
                checkOver += 1
                d.append(depth)
                if parent:
                    par.append(parent.val)
                else:
                    par.append(-10000)
            if checkOver == 2:
                break
            if node.left:
                Q.append((node.left, depth+1, node))
            if node.right:
                Q.append((node.right, depth+1, node))
        if d[0] == d[1] and par[0] != par[1]:
            return True
        return False

102. 二叉树的层次遍历

"""
BFS - 利用set来记录层数
"""
class Solution:
    def levelOrder(self, root: TreeNode):
        if root == None:
            return []
        Q = [(root, 1)]
        deepSet = set()
        deepSet.add(1)
        tmp = []
        result = []
        while len(Q) != 0:
            node, deepth = Q.pop(0)
            if deepth not in deepSet:
                deepSet.add(deepth)
                result.append(tmp)
                tmp = []
            tmp.append(node.val)
            if node.left:
                Q.append((node.left, deepth+1))
            if node.right:
                Q.append((node.right, deepth+1))
        result.append(tmp)
        return result

103. 二叉树的锯齿形层次遍历 - 和二叉树遍历完全一致

"""
两者代码的唯一不同在于锯齿形的遍历编号从0开始的奇数行需要逆转一下
"""
class Solution:
    def zigzagLevelOrder(self, root: TreeNode):
        if root == None:
            return []
        Q = [(root, 1)]
        deepSet = set()
        deepSet.add(1)
        tmp = []
        result = []
        while len(Q) != 0:
            node, deepth = Q.pop(0)
            if deepth not in deepSet:
                deepSet.add(deepth)
                result.append(tmp)
                tmp = []
            tmp.append(node.val)
            if node.left:
                Q.append((node.left, deepth+1))
            if node.right:
                Q.append((node.right, deepth+1))
        result.append(tmp)
        # 唯一的差别就在这里
        for i in range(len(result)):
            if i % 2 == 1:
                result[i] = result[i][::-1]
        return result

127. 单词接龙 - 双向BFS

"""
使用最普通BFS模板会超时(暂无解决办法),本题可以思考为一棵树,根节点就是beginWord,它的子节点就是变换一个单词后的单词,子节点的子节点就是子节点变换一个单词... 然后在那一层发现了目标节点,返回该层的层数
"""
class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList) -> int:
        if beginWord == endWord:
            return 0
        Q = []
        for i in wordList:
            if self.OneDefferent(i, beginWord):
                Q.append((i, 1))
        s = set()
        while len(Q) != 0:
            word, step = Q.pop(0)
            # print(word)
            if word == endWord:
                return step+1
            if word in wordList:
                wordList.remove(word)
            for i in wordList:
                if self.OneDefferent(i, word):
                    Q.append((i, step+1))
        return 0

    def OneDefferent(self,str1, str2):
        str1 = list(str1); str2 = list(str2)
        check = 0
        for i in range(len(str2)):
            if str1[i] != str2[i]:
                check += 1
            if check > 1 :
                return False
        if check == 1:
            return True
"""
评论中提到的双向BFS(还在理解中):
	当某层数量过大的时候,BFS会耗时很多。所以采用两端一起走的方式,不断比较,那一头走的少就走那一头,如果有交集最后肯定会相遇。
"""
class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList) -> int:
        if endWord not in wordList:
            return 0
        head = {beginWord}
        tail = {endWord}
        wordSet = set(wordList)
        wordSet.remove(endWord)
        res = 0
        while head and tail:
            res += 1
            if len(head) > len(tail):
                head, tail = tail, head

            nextLevel = set()
            for i in head:
                for j in range(len(i)):
                    for letter in range(97, 97+26):
                        # 利用二十六个字母在每一个位置进行替换
                        newWord = i[:j] + chr(letter) + i[j+1:]
                        if newWord in tail:
                            return res + 1
                        if newWord not in wordSet:
                            continue
                        wordSet.remove(newWord)
                        nextLevel.add(newWord)
            head = nextLevel
        return 0
"""
BFS双向的模板:适用于从某个初始状态到某个终止状态求最短路径

head = {初始状态}
tail = {终止状态}

while head and tail:
    # 每次都从短的开始
    if len(head) > len(tail):
        head, tail = tail, head

    nextLeval = set()
    for i in head:
        # 扩展下一层
        if 扩展的下一层的某个元素 in tail:
            # 表示已经找到了
            return

    head = nextLevel
    # 每次的head和tail都在更新为某层的状态

"""

433. 最小基因变化 - 套用上面的双向BFS模板

"""
和上面的单词结论几乎一致,都是每次给定一个初始状态、一个终止状态,改变一个字母,找到最小的变化(其实也就是找到最小路径)
"""
class Solution:
    def minMutation(self, start: str, end: str, bank) -> int:
        change = ["A", "C", "G", "T"]
        if end not in bank or len(bank) == 0:
            return -1
        head = {start}
        tail = {end}
        bank.remove(end)
        res = 0
        while head and tail:
            res += 1
            if len(head) > len(tail):
                head, tail = tail, head

            nextLevel = set()
            # 拓展下一层
            for i in head:
                for j in range(len(i)):
                    for cha in change:
                        newGene = i[:j]+cha+i[j+1:]
                        if newGene in tail:
                            return res
                        if newGene not in bank:
                            continue
                        nextLevel.add(newGene)
                        # 已经走过的就不用再走了
                        bank.remove(newGene)
            head = nextLevel
        return -1
posted @ 2019-11-19 15:03  但是我拒绝  阅读(338)  评论(1编辑  收藏  举报