LeetCode | Tree

2022-4-27

哭唧唧,昨天做的记录没有保存,算啦1-d dp再做一遍好啦当加深记忆啦!当然要记得及时保存哈!

226. Invert Binary Tree

  • 主要思路:dfs | 当前根节点的左右两个子孩子交换位置,问题就转化成了两个子孩子作为根节点的反转问题;
    • version2为version1的简化版本,本质没啥区别;
class TreeNode:
	def __init__(self, val=0, left=None, right=None):
		self.val = val
        self.left = left
        self.right = right
        
class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return None
        
        # 当前节点左右子节点交换位置
        tmp = root.left
        root.left = root.right
        root.right = tmp
        
        root.left = self.invertTree(root.left)    # 左子树反转
        root.right = self.invertTree(root.right)  # 右子树反转
        return root
        
    def invertTree2(self, root: TreeNode) -> TreeNode:
        if not root:
            return None
        root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)
        return root

104. Maximum Depth of Binary Tree

  • 递归杀我千百回
  • 跟neetcode的日常
  • 主要思路:neetcode主要给出了三种解法
  1. RECURSIVE DFS:当前节点的depth = 左右孩子的最大深度 + 1 【不用担心当前节点如果是None会不会也+1了,在base case的时候已经过滤掉了None节点】

  2. ITERATIVE DFS | stack:stack存放[node, depth];root放进去stack,pop出来,放左右节点;每次pop都更新下最大深度res;后面就是pop栈顶元素,更新res,栈顶元素左右节点和depth信息压栈,loop直到栈空了;

    头一次遇到stack可以同时存放node和depth的!是我愚钝了![之前遇到的要么就是node要么就放index哈哈哈]
    在这里插入图片描述

  3. BFS | queue:

    1. 该层节点放进去,记录depth
    2. 队首pop出来,队尾加进去pop出来的节点的左右孩子(如果有的话),记录depth;
    3. 重复2操作,直到queue为空;

    可能会想问为什么要用队列呢?考虑以下队列的性质,先进先出的性质比较符合bfs的逻辑;而stack的前进后出的性质比较符合dfs的逻辑;

    • depth的更新逻辑是while进去都是当前层的node在里面,for的是当前层的node,虽然append了node的左右子节点,按照逻辑来说append之后没有改变当前层的len(q),应该是在下次进去while之后queue已经把前一层的node全pop掉了,又变成了下一层(现在的当前层)的所有node了;
      注意要处理root is None的case;
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def maxDepth_re_dfs(self, root) -> int:
        if not root:
            return 0
        return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))

    def maxDepth_it_dfs(self, root) -> int:
        if not root:
            return 0

        stack = [[root, 1]]
        res = 0

        while stack:
            node, depth = stack.pop()

            res = max(res, depth)
            if node.left:
                stack.append([node.left, depth + 1])
            if node.right:
                stack.append([node.right, depth + 1])
        return res

    def maxDepth_it_dfs2(self, root) -> int:
        stack = [[root, 1]]
        res = 0

        while stack:
            node, depth = stack.pop()
            if node:
                res = max(res, depth)
                stack.append([node.left, depth + 1])
                stack.append([node.right, depth + 1])
        return res


    def maxDepth_bfs(self, root) -> int:
        if not root:
            return 0

        from collections import deque
        q = deque([root])
        depth = 0

        while q:
            for _ in range(len(q)):
                node = q.popleft()
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            depth += 1
        return depth
    
    def maxDepth_bfs2(self, root) -> int:
        from collections import deque
        q = deque([root])
        depth = 0

        while q:
            for _ in range(len(q)):
                node = q.popleft()
                if node:
                    q.append(node.left)
                    q.append(node.right)
            depth += 1
        return depth - 1 

ps 2.的v1和v2以及3.的v1和v2就是在处理边界的时候稍微修改了一下;目前而言感觉还是v1的比较好理解符合逻辑,v2的话空节点也会压栈,但是可以一起处理一开始根节点为空的情况;嗐,各有所长吧;

2022-5-7 重新过了一遍dfs,果然我是不会写的那么简洁的orz【我的逻辑g了哈哈哈哈】
那三句实际上可以合并成return 1+max(dfs(root.left, depth),dfs(root.right))

class Solution:
    def maxDepth(self, root):
        def dfs(root, depth):
            if not root:
                return depth
            depth += 1
            depth = max(dfs(root.left, depth), dfs(root.right, depth))
            return depth
        return dfs(root, 0)

顺便把BFS系列过一遍

BFS

102. Binary Tree Level Order Traversal

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return []

        from collections import deque
        q = deque([root])
        res = []

        while q:
            tmp = []
            for _ in range(len(q)):
                node = q.popleft()
                tmp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            res.append(tmp)
        return res

107. Binary Tree Level Order Traversal II

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def levelOrderBottom(self, root: TreeNode):
        if not root:
            return []

        from collections import deque
        q = deque([root])
        res = []

        while q:
            tmp = []
            for _ in range(len(q)):
                node = q.popleft()
                tmp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            res.insert(0, tmp)
        return res

199. Binary Tree Right Side View

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def rightSideView(self, root):
        if not root:
            return []

        from collections import deque
        q = deque([root])
        res = []

        while q:
            tmp = []
            for _ in range(len(q)):
                node = q.popleft()
                tmp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            res.append(tmp[-1])
        return res

637. Average of Levels in Binary Tree

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def averageOfLevels(self, root):
        from collections import deque
        q = deque([root])
        res = []

        while q:
            tmp = []
            for _ in range(len(q)):
                node = q.popleft()
                tmp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            res.append(sum(tmp) / len(tmp))
        return res

429. N-ary Tree Level Order Traversal

class TreeNode:
    def __init__(self, val=0, children=None):
        self.val = val
        self.children = children
class Solution:
    def levelOrder(self, root):
        if not root:
            return []
        from collections import deque
        q = deque([root])
        res = []

        while q:
            tmp = []
            for _ in range(len(q)):
                node = q.popleft()
                tmp.append(node.val)
                if node.children:
                    q.extend(node.children)
            res.append(tmp)
        return res

515. Find Largest Value in Each Tree Row

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def largestValues(self, root):
        if not root:
            return []

        from collections import deque
        q = deque([root])
        res = []

        while q:
            tmp = float("-inf")
            for _ in range(len(q)):
                node = q.popleft()
                tmp = max(tmp, node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            res.append(tmp)
        return res

116. Populating Next Right Pointers in Each Node

这道题不需要存val;边连边存层;这里默认next是None所以range(len(q) - 1)就可以了;

class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next

class Solution:
    def connect(self, root):
        if not root:
            return root

        from collections import deque
        q = deque([root])

        while q:
            for i in range(len(q) - 1):
                q[i].next = q[i + 1]

            for _ in range(len(q)):
                node = q.popleft()
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
        return root

117. Populating Next Right Pointers in Each Node II

和116一样可过;

104. Maximum Depth of Binary Tree

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def maxDepth(self, root) -> int:
        if not root:
            return 0

        from collections import deque
        q = deque([root])
        depth = 0

        while q:
            for i in range(len(q)):
                node = q.popleft()
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            depth += 1
        return depth

111. Minimum Depth of Binary Tree

相比104:当遇到左右孩子都空时,说明该节点是其中一条路径的终点了,可以提前终止了;

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def minDepth(self, root):
        if not root:
            return 0

        from collections import deque
        q = deque([root])
        depth = 0

        while q:
            depth += 1
            for _ in range(len(q)):
                node = q.popleft()
                if not node.left and not node.right:
                    return depth
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
        return depth

543. Diameter of Binary Tree

  • 思路很明显去记录下每个节点左右子树的最大深度的和,注意复用;

自己写dfs还是会卡住!!

  • 求二叉树的最大深度模块[104]就可以复用了,空节点返回-1真的绝!
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def diameterOfBinaryTree(self, root):
        res = [0]
        def dfs(root):
            if not root:
                return -1

            left = dfs(root.left)
            right = dfs(root.right)
            res[0] = max(res[0], 2+left+right)
            return 1 + max(left, right)
        dfs(root)
        return res[0]

110. Balanced Binary Tree

  • 还是复用dfs的104模块!
  • 这道题的关键在与如何保存下面节点是不是平衡的信息
    • 为了和543看起来差不多我们还是选择使用res全局变量来搞;
    • 我们要知道这是一个dfs到最后再逐步往上check的过程,也就是说如果下面有一个节点不平衡的时候res[0]的状态就改为False了,好像没法提前终止返回,所以后面就算节点是平衡的也不需要改变res[0]的状态了;状态改为false之后不管你之后平不平衡都已经无所谓了
      所以修改的条件为:
      if res[0] and (left - right > 1 or right - left > 1): res[0] = False
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def isBalanced(self, root):
        res = [True]
        def dfs(root):
            if not root:
                return -1
            
            left = dfs(root.left)
            right = dfs(root.right)
            if res[0] and (left - right > 1 or  right - left > 1):
                res[0] = False
            return 1 + max(left, right)
        dfs(root)
        return res[0]

100. Same Tree

属于边dfs边check的类型,和226差不多

  • 比较节点:
    1. 终止条件:都是空的 说明到了根节点,两边结构相同;
    2. 终止条件:一边空一边不空,说明两边结构不同;
    3. 值不等;
class TreeNode:
    def __init__(self, val=0, right=None, left=None):
        self.val = val
        self.right = right
        self.left = left

class Solution:
    def isSameTree(self, p, q):
        if not p and not q:
            return True
        if (not p and q) or (p and not q): # if not p or not q:
            return False
        if p.val != q.val:
            return False
        return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)

572. Subtree of Another Tree

  • 我的直观:从根节点开始判断是否是同一棵树(复用[100]),不是判断左右子树[相当于每个节点都判断了一遍是否是Same Tree]
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def isSubtree(self, root, subRoot):
        def isSameTree(p, q):
            if not p and not q:
                return True
            if not p or not q:
                return False
            if p.val != q.val:
                return False
            return isSameTree(p.left, q.left) and isSameTree(p.right, q.right)
        if not root:
            return False
        if isSameTree(root, subRoot):
            return True
        return self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)

235. Lowest Common Ancestor of a Binary Search Tree

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值