代码随想录算法训练营 Day 18|513.找树左下角的值, 112. 路径总和, 113.路径总和ii, 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

Day 18|513.找树左下角的值, 112. 路径总和, 113.路径总和ii, 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

513.找树左下角的值

思路

可以用层序遍历,返回层序遍历最后一行的第一个。

尝试层序遍历:

class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        if not root:
            return root
        queue = deque([root])
        result = []
        while queue:
            tmp = []
            for _ in range(len(queue)):
                node = queue.popleft()
                tmp.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            result.append(tmp)
        return result[-1][0]

成功通过!

递归遍历思路:
最底层,首先要用二叉树的最大深度判断。求最大深度要用前序遍历。
最左边,也就是遍历到的第一个符合最大深度的值。
不知道如何写代码

根据代码随想录:
要点:

  1. 本题用前中后序都可以,只要遍历时先遍历左边就好了
  2. 本题需要两个全局变量,maxDepth记录最大深度,result记录最大深度最左边的值。
  3. 递归函数的参数中,有个depth,记录当前深度
  4. 终止条件:遇到叶子节点,更新最大深度
  5. 单层递归需要用到回溯
  6. 本题没有中的处理逻辑

尝试写代码

class Solution:
    result = 0
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        if not root:
            return None
        maxDepth = 0
        # result = 0
        self.traversal(root, 0, maxDepth, Solution.result)
        return Solution.result

    def traversal(self, node, depth, maxDepth, result):
        if not node.left and not node.right:
            if depth > maxDepth:
                maxDepth = depth
                result = node.val
        if node.left:
            depth += 1
            self.traversal(node.left, depth, maxDepth, result)
            depth -= 1
        if node.right:
            depth += 1
            self.traversal(node.right, depth, maxDepth, result)
            depth -= 1

最终结果为0,result的值没有改变。不知道如何处理全局变量。

Python注意:

  1. 全局变量用self.xxx

最终代码:

class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        if not root:
            return None
        self.maxDepth = float('-inf')
        self.result = 0
        self.traversal(root, 0)
        return self.result

    def traversal(self, node, depth):
        if not node.left and not node.right:
            if depth > self.maxDepth:
                self.maxDepth = depth
                self.result = node.val
            return
        if node.left:
            depth += 1
            self.traversal(node.left, depth)
            depth -= 1
        if node.right:
            depth += 1
            self.traversal(node.right, depth)
            depth -= 1

112. 路径总和

思路

用targetsum的值减去遍历到的每个节点,如果到叶子几点,值为0,则返回True

问题:
如果遍历到叶子节点,符合题目要求,返回True,这个返回值要如何传递回去?是通过二叉树一层层返回,还是用一个变量专门记录?
使用全局变量result记录,如果遇到一个满足条件的结果,result = True。
没有中的处理逻辑,在处理左右逻辑时,用sum减去节点的值,并且用到回溯

尝试写代码:

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        self.result = False
        self.traversal(root, targetSum)
        return self.result 

    def traversal(self, node, sum):
        if not node.left and not node.right:
            if sum == 0:
                self.result = True
            return

        if node.left:
            sum -= node.left.val
            self.traversal(node.left, sum)
            sum += node.left.val
        if node.right:
            sum -= node.right.val
            self.traversal(node.right, sum)
            sum += node.right.val

测试用例通过,但如果只有一个节点,则错误。
是因为缺少对根节点的处理。

根据代码随想录视频:
要点:

  1. 递归解法首先确定遍历顺序,本题用前中后序都可以。
  2. 如果找到一条路径,立刻返回,因此函数有返回值,通过二叉树一路返回上去。函数中还需要一个计数参数count,放入目标值,一路减去遍历的节点值。
  3. 终止条件:叶子节点且count为0,返回True;叶子节点且count不为0,返回False
  4. 由于函数返回只需要一层层传递上去,左右逻辑中的递归函数调用也需要判断其返回结果,如果为True,则继续返回True。最后函数结尾,返回False。
  5. 注意根节点的值要首先剪掉。

最终代码:

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        return self.traversal(root, targetSum - root.val)

    def traversal(self, node, sum):
        if not node.left and not node.right and sum == 0:
            return True
        elif not node.left and not node.right and sum != 0:
            return False

        if node.left:
            sum -= node.left.val
            if self.traversal(node.left, sum):
                return True
            sum += node.left.val
        if node.right:
            sum -= node.right.val
            if self.traversal(node.right, sum):
                return True
            sum += node.right.val
        return False

总结

自己的思路基本上想到了递归的顺序,想到了回溯的过程,甚至想到了直接用给定值减去遍历的节点,只是对于返回值的处理还需要整理。因为本题只要有一个答案就可以返回True,因此不需要遍历全部的二叉树,所以遇到满足条件的,直接返回True就行。此外,需要了解递归过程中的首尾值的处理,这里的单层递归逻辑中,没有处理到根节点,需要在一开始处理。

113.路径总和ii

思路

在上一题的基础上,新增一个函数参数path,用于记录遍历的路径。

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if not root:
            return []
        self.result = []
        self.traversal(root, targetSum - root.val, [root.val])
        return self.result

    def traversal(self, node, count, path):
        if not node.left and not node.right and count == 0:
            self.result.append(path.copy())
            return
        if not node.left and not node.right:
            return

        if node.left:
            count -= node.left.val
            path.append(node.left.val)
            self.traversal(node.left, count, path)
            count += node.left.val
            path.pop()
        if node.right:
            count -= node.right.val
            path.append(node.right.val)
            self.traversal(node.right, count, path)
            count += node.right.val
            path.pop()
        return

成功通过!
只是在记录path的过程中,如果只是result.append(path),那result的值会跟着path动态改变。
改变:需要加入path的全部值,注意代码细节,应写为result.append(path[:])

根据代码随想录:
注意:

  1. 熟练运用python的类的特性,如果一个参数,类中的多个方法都用到了,就用self设为类内全局变量或成员变量。不需要设置为函数参数。
  2. 不知道为什么,需要写成这样的形式:result.append(path[:]),原先的就不行。??
  3. 答:Python里不写[:]代表的是传的是引用,会变,带上就是拷贝的结果,相当于快照

最终代码:

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if not root:
            return []
        self.result = []
        self.path = [root.val]
        self.traversal(root, targetSum - root.val)
        return self.result

    def traversal(self, node, count):
        if not node.left and not node.right and count == 0:
            self.result.append(self.path[:])
            return
        if not node.left and not node.right:
            return

        if node.left:
            count -= node.left.val
            self.path.append(node.left.val)
            self.traversal(node.left, count)
            count += node.left.val
            self.path.pop()
        if node.right:
            count -= node.right.val
            self.path.append(node.right.val)
            self.traversal(node.right, count)
            count += node.right.val
            self.path.pop()
        return

106.从中序与后序遍历序列构造二叉树

思路

首先根据后序,能判断出根节点就是后序遍历中的最后一个值,然后在中序遍历中寻找这个值,并以此为分界,左边的是左子树,右边是右子树。
然后递归,再从后序找到左子树/右子树的根节点,重复以上过程。
前序遍历写递归。
问题
题目说返回二叉树,是要返回输出中包含null的列表,还是只需要返回根节点?
如果返回根节点,那二叉树中的各个节点该如何构造
尝试以返回根节点写代码
具体结合后序遍历与中序遍历,分离出左/右子树的中后序遍历。
终止条件:如果左右的中/后序遍历列表为空

尝试写代码:

class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
        root = TreeNode(-1)
        self.traversal(root, inorder, postorder)
        return root

    def traversal(self, node, inorder, postorder):
        if not inorder and not postorder:
            return

        node.val = postorder[-1]
        index = inorder.index(node.val)
        left_inorder = inorder[:index]
        right_inorder = inorder[index + 1:]

        left_postorder = postorder[:len(left_inorder)]
        right_postorder = postorder[len(left_inorder):len(right_inorder) + 1]

        self.traversal(node.left, left_inorder, left_postorder)
        self.traversal(node.right, right.inorder, right_postorder)

出错,node.val赋值出错。
不知道如何给新的二叉树赋值。

根据代码随想录视频:
要点:

  1. 后续数组为0,空节点
  2. 后续数组最后一个元素为节点元素
  3. 寻找中序数组位置,做切割点
  4. 切中序数组
  5. 切后续数组
  6. 递归处理左区间右区间

最终代码:

class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
        if not postorder:
            return None

        root_val = postorder[-1]
        root = TreeNode(root_val)

        separator_idx = inorder.index(root_val)

        inorder_left = inorder[:separator_idx]
        inorder_right = inorder[separator_idx + 1:]

        postorder_left = postorder[:len(inorder_left)]
        postorder_right = postorder[len(inorder_left): len(postorder) - 1]

        root.left = self.buildTree(inorder_left, postorder_left)
        root.right = self.buildTree(inorder_right, postorder_right)
        return root

Python中list的查找方法

  1. in:判断是否在列表中
  2. count():统计给定值在列表中出现的次数
  3. index:查看给定值在列表中的位置

105.从前序与中序遍历序列构造二叉树

思路

构造二叉树的细节与上一题相似,只是划分中序遍历区间时,利用前序遍历。

最终代码:

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:

        if not preorder:
            return None

        root_val = preorder[0]
        root = TreeNode(root_val)

        separator_idx = inorder.index(root_val)

        inorder_left = inorder[:separator_idx]
        inorder_right = inorder[separator_idx + 1:]

        preorder_left = preorder[1:1 + len(inorder_left)]
        preorder_right = preorder[1 + len(inorder_left):]

        root.left = self.buildTree(preorder_left, inorder_left)
        root.right = self.buildTree(preorder_right, inorder_right)
        return root
  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值