微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

树更新至8.24

公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

其实吧,这题我用一种偏复杂的方法做了。
我的方法:每次递归返回两个值:①有无结点1?②有无结点2?第一次两边都有的就是结果。

题解的方法:每次递归只返回一个值:是否存在结点1或者结点2。然后分几种情况讨论:
①两边都没有:返回None
②有一边没有:返回另一边
③两边都有:返回root

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if root is None: return
        if root.val == p.val or root.val == q.val: return root
        a = self.lowestCommonAncestor(root.left, p, q)
        b = self.lowestCommonAncestor(root.right, p, q)
        if a and b: return root
        if a is None: return b
        if b is None: return a

说几个要点
1.前置增加判断条件:若碰到p后者q,直接停止递归往上回溯,因为公共祖先一定不可能在下面,已经没有往下走的必要了。(这里是先序遍历
2.后面的判断是后序遍历,请注意a和b的值是一直传递上去的,而并不是重新定义。也就是说,如果底部一个结点遍历到了p的值,会一直顺着回溯方向往上传递

先普及一下树的概念。
树的高度:从叶子结点开始计算——后序遍历
树的深度:从根节点从0开始计算——先序遍历或者 直接在递归函数参数上进行一次+1

传染树

给你一棵二叉树的根节点 root ,二叉树中节点的值 互不相同 。另给你一个整数 start 。在第 0 分钟,感染 将会从值为 start 的节点开始爆发。

每分钟,如果节点满足以下全部条件,就会被感染:

节点此前还没有感染。
节点与一个已感染节点相邻。
返回感染整棵树需要的分钟数。

在这里插入图片描述


法一:
考虑情况。
①感染结点就是当前root——求的是向下的距离,也就是感染结点的高度 - 1
②当前遍历root的左子树有感染结点——求的是向上的距离,= 右子树高度 + (感染结点深度 - 当前深度)
③右子树有感染结点——如法炮制
④两边都没有——不用计算,但就算计算了也不可能是最大值,也可以不把他当成一种特殊情况。

class Solution:
    def __init__(self):
            self.start_depth = -1 #储存感染结点的深度,初始值为-1
            self.start = 3
            self.res = 0
    def order(self, root, depth):
            if (root == None):
                return 0
            l = self.order(root.left, depth + 1)
            inleft = self.start_depth != -1
            r = self.order(root.right, depth + 1)
            inright = self.start_depth != -1
            if (root.val == self.start):
                self.start_depth = depth
                self.res = max(self.res, max(l, r))
            if(inleft):
                self.res = max(self.res, r + self.start_depth - depth)
            elif(inright):
                self.res = max(self.res, l + self.start_depth - depth)
            return max(l, r) + 1
    def amountOfTime(self, root: Optional[TreeNode], start: int) -> int:
        self.start = start
        self.order(root, 0)
        return self.res

说一下重要的点:
为什么要设置深度和高度两个参数?不能都用一个来计算吗?
当然不能。当遍历到某个节点出现情况②/③时,你并不能拿到到最底层叶子结点的深度,所以情况②的右子树只能用高度求。
情况②的左子树只能用深度差求,如果用高度差求,你不能保证感染结点在你最长的那条路径下面。考虑一个例子:[1,2,3,4,5(感染),null, null, 6],遍历到1的时候,不能用高度差求左子树的和,画个图就知道了。

法二
法二用到了很清新的思路:将树转换为图!这个思路太好理解了,转换为图之后以感染点作为起点,计算时间即可!

class Solution:
    def amountOfTime(self, root: Optional[TreeNode], start: int) -> int:
        
        graph = collections.defaultdict(list)   # 无向图
        
        # 一次BFS:层次遍历 + 建图
        deque = collections.deque([root])
        while deque:
            for _ in range(len(deque)):
                node = deque.popleft()
                if node.left:
                    deque.append(node.left)
                    graph[node.val].append(node.left.val)
                    graph[node.left.val].append(node.val)
                if node.right:
                    deque.append(node.right)
                    graph[node.val].append(node.right.val)
                    graph[node.right.val].append(node.val)
        
        # 二次BFS:模拟感染(SI疾病传播模型)
        deque = collections.deque([start])
        visited = set([start])
        time = -1
        while deque:
            for _ in range(len(deque)):
                node = deque.popleft()
                for neighbor in graph[node]:
                    if neighbor not in visited:
                        visited.add(neighbor)
                        deque.append(neighbor)
            time += 1
        
        return time

原文地址:https://www.jb51.cc/wenti/3283722.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐