leetcode关于树的问题

链表和树路径的匹配。

解释: 链表是否存在于树的某条路径中。

Tips:

  • 从以结点为头的路径,还是左右子路径dfs(node) or subpath(left) or subpath(right)
  • 在这里插入图片描述
class Solution:
    def dfs(self, head: ListNode, rt: TreeNode) -> bool:
        if not head:
            return True
        if not rt:
            return False
        if rt.val != head.val:
            return False
        return self.dfs(head.next, rt.left) or self.dfs(head.next, rt.right)

    def isSubPath(self, head: ListNode, root: TreeNode) -> bool:
        if not root:
            return False
        return self.dfs(head, root) or self.isSubPath(head, root.left) or self.isSubPath(head, root.right)

2 树的层次遍历(BFS)

tips:

  • 队列伺候bfs, 节点不为空,队列就加入左右儿子
  • level层保存着本层的数据
    实例:
    二叉树:[3,9,20,null,null,15,7],
class Solution(object):
    def levelOrder(self, root):
        queue = []
        queue.append(root)
        res = []
        while queue:
            
            level = []
            for _ in range(len(queue)):
                cur = queue.pop(0)
                if not cur: #不为null我就加
                    continue
                level.append(cur.val)
                queue.append(cur.left)
                queue.append(cur.right)
            #整完一看。level啥样,如果是空不要了,不然就添加到结果
            if level:
                res.append(level)
        return res

3 树的深度

Tips:

  • 递归求解,深度等于左右子节点的深度最大值+1
  • root的深度为0
    在这里插入图片描述
class Solution:
	  def Depth(self, root: TreeNode) -> int:
        if not root:
            return 0
        return 1 + max(self.Depth(root.left), self.Depth(root.right)) 

4 树的最小深度

Tips:

  • 和最大深度类似,取最小即可
  • 但是注意,当深度为0, 就不算了,因为深度是叶子节点到根节点的距离!没有叶子自然不算
    在这里插入图片描述
class Solution:
    @functools.lru_cache()
    def minDepth(self, root: TreeNode) -> int:
        if not root : 
            return 0
        leftDepth = self.minDepth(root.left)
        rightDepth = self.minDepth(root.right)
        childDepth = min(leftDepth, rightDepth) if leftDepth and rightDepth else leftDepth or rightDepth
        return 1 + childDepth

5 判断AVL平衡树

Tips:

  • 首先,写出求深度的函数
  • 然后,判断以每一个结点为root的树,是否是平衡的abs(left-right)<=1
class Solution:
    # 计算以当前节点为根的树深度
    def Depth(self, root: TreeNode) -> int:
        if not root:
            return 0
        return 1 + max(self.Depth(root.left), self.Depth(root.right))

    def isBalanced(self, root: TreeNode) -> bool:
        # 空树是AVL
        if not root:
            return True
        # 若左右子树深度超过1,非AVL
        if abs(self.Depth(root.left) - self.Depth(root.right)) > 1:
            return False
        # 递归执行,当出现不满足AVL性质的子树时,执行短路运算立即返回结果
        return self.isBalanced(root.left) and self.isBalanced(root.right)

6 树的最大路径和

Tips:

  • 路径的种类有三种,左中右,左中上,右中上
  • 如果某个贡献值<0? 那就果断不选这个,取0即可
  • 全局变量保存目前的最大值,因为不一定经过根节点,最后递归肯定是回归到根节点。
  • 在这里插入图片描述
class Solution:
    def __init__(self):
        self.maxSum = float("-inf")#全局变量记录最大和
    def maxPathSum(self, root: TreeNode) -> int:
        def maxGain(node):
            if not node:
                return 0
            # 递归计算左右子节点的最大贡献值
            # 加了负数,不如不加
            leftGain = max(maxGain(node.left), 0)
            rightGain = max(maxGain(node.right), 0)
            # 左中右路径
            priceNewpath = node.val + leftGain + rightGain 
            # 更新答案
            self.maxSum = max(self.maxSum, priceNewpath)
            # 返回节点的最大贡献值
            return node.val + max(leftGain, rightGain)
        maxGain(root)
        return self.maxSum

7 收集叶子节点

Tips: 统计height

  • res[height]=[] 里面加入height这个高度的节点

在这里插入图片描述
在这里插入图片描述

class Solution(object):
    def findLeaves(self, root):
        if not root:
            return []
        self.res = []
        self.delLeaves(root)
        return self.res

    def delLeaves(self, root):#返回节点树的高度
        if root == None:
            return -1
        leftHeight = self.delLeaves(root.left)
        rightHeight = self.delLeaves(root.right)
        height = max(leftHeight, rightHeight) + 1
        
        #处理全局变量
        if height == len(self.res):
            self.res.append([])
        self.res[height].append(root.val)
        
        return height

8 n个节点的二叉搜索树种类

tips:

  •  卡特兰数
    

C a t n = C 2 n n − C 2 n n − 1 = C 2 n n n + 1 = C a t n − 1 × 2 ( 2 n − 1 ) n + 1 Cat_n = C_{2n}^n - C_{2n}^{n-1} = \frac {C_{2n}^n}{n+1} = Cat_{n-1} \times \frac{2(2n-1)}{n+1} Catn=C2nnC2nn1=n+1C2nn=Catn1×n+12(2n1)
在这里插入图片描述

class Solution(object):
    '''
    卡特兰数
    Catalan(n) = C(n,2n)/(n+1) = C(n,2n) - C(n-1, 2n) = Catalan(n-1)*2(2n-1)/n+1
    '''
    def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """
        C = 1
        for i in range(0, n):
            C = C * 2*(2*i+1)/(i+2)
        return int(C)

7 n节点的二叉搜索树集合

tips:

  • BST有个特点,有顺序!
  • 遍历数组,任何一个位置i的左边都可以成左子树,右边成为右子树。
  • 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
    
class Solution:
    def generateTrees(self, n: int) -> List[TreeNode]:
        def generateTrees(start, end):
            if start > end:
                return [None]     

            allTrees = []
            for i in range(start, end + 1):  # 枚举可行根节点
                # 获得所有可行的左子树集合
                leftTrees = generateTrees(start, i - 1)
                # print(leftTrees)
                # 获得所有可行的右子树集合
                rightTrees = generateTrees(i + 1, end)
                
                # 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
                for l in leftTrees:
                    for r in rightTrees:
                        currTree = TreeNode(i) #树根节点
                        currTree.left = l
                        currTree.right = r
                        #记录下来
                        allTrees.append(currTree)
            return allTrees
            
        return generateTrees(1, n) if n else []

8 翻转二叉树

tip:

  • 每一个结点的左子树和右子树互换
  • 然后再换左右子树的子树,recursively
  • 返回树,也就是root
class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return None
        root.left, root.right = root.right, root.left

        self.invertTree(root.left)
        self.invertTree(root.right)
        return root  # 这句话就很棒
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万物琴弦光锥之外

给个0.1,恭喜老板发财

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值