剑指offer(python)-题目25-二叉树和为某一值的路径

题目描述
输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

not x 意思相当于 if x is false, then True, else False

代码中经常会有变量是否为None的判断,有三种主要的写法:

第一种是if x is None;

第二种是 if not x:;

第三种是if not x is None(这句这样理解更清晰if not (x is None))

思路1:–递归

首先要理解题意,是从根节点往子节点连。

1、如果只有根节点或者找到叶子节点,我们就把其对应的val值返回

2、如果不是叶子节点,我们分别对根节点的左子树、右子树进行递归,直到找到叶子结点。然后遍历把叶子结点和父节点对应的val组成的序列返回上一层;如果没找到路径,其实也返回了序列,只不过是[]

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def FindPath(self, root,target_number):
        result =[]
        if not root:
            return result
        if not root.left and not root.right and root.val == target_number:
            return [[root.val]]
        else:
            left = self.FindPath(root.left,target_number - root.val)
            right = self.FindPath(root.right,target_number - root.val)
            for item in left+right:
                result.append([root.val]+item)
            return result

原文:https://blog.csdn.net/zjxxyz123/article/details/79699575
思路2:和思路1类似的想法,但是提出了一些python的注意事项

这是一道DFS题目,也可以看做是先序遍历的题目 ,在二叉树中,dfs就相当于先序遍历
首先,采用一种“减法”思想,当检查一棵树从根到叶子节点形成的路径的和是否为target时,先将当前根节点的值 root.val
加入path, 然后检查它的左子树(若非空),看从左子树的根到叶子节点形成的路径的和是否为 target - root.val (递归),
然后同样的道理去递归检查右子树(若非空),这便是大致的思路。 但这道题麻烦的一点是,它要求记录下所有符合标准的路径,这便用到了dfs的特性。
但又来了一件麻烦事,先序遍历便是先左后右。检查完左子树后,会对path就行修改,再去查找右子树,如何将path恢复到之前未进行左子树检查的状态?

一开始自己的做法是,每到分叉路口,到对当前路径做一份拷贝,用原路径去继续进行左子树的递归,拷贝路径进行右子树的递归,这样左子树对右子树的结果产生影响,但是这样造成了大量的拷贝,浪费空间
比较好的做法是将path设为全局的,然后dfs的过程便是先序遍历的过程,一旦遍历到叶子结点,便将path最后的节点移除掉,这样在递归一层一层进行的时候将值添加进path,在递归返回的过程中将path最末尾的元素一个一个移除。这样便依靠递归的特性完成了路径的恢复。

例如对于树 10,5,12,5,7,#,#,#,#,#,#,#,#(层序遍历),path变化过程为 10,5,5 》》 10,5 》》
10,5,7 》》10,5 》》10 》》10,12 》》10 》》 null

因为最终遍历到叶子结点时,若发现符合规定的路径,是把path加入到结果集中,因为java中添加的是引用,而path是不断变化的,所以我们要新new一个当前路径的副本出来,防止添加进去的path都是相同的(最终path的状态)。

当然,这道题也可以用加法的思想,看dfs过程中能否加出target

因为题意没有说节点值全为正数,所以必须递归到根节点才能确定这条路径能否加出target,而不能到中间节点就加到>=target了,就认为这条路径不行了,假如这条路径后序有0或者负数的情况,还是能加出target的。
经验教训 深刻理解DFS的用法 深刻理解递归是如何恢复path的,从先序遍历进行考虑,递归是如何一步步进行的,如何一步步返回的
最终添加入结果集中,必须添加的是path的副本 递归中,全局变量的使用

# -*- coding:utf-8 -*-
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        # write code here
        if not root:
            return []
 
        ret = []
        path = []
        self.Find(root, expectNumber, ret, path)
        # print ret
        # a = [];self.f(a);print a
        return ret
     
    def Find(self, root, target, ret, path):
        if not root:
            return
 
        path.append(root.val)
        isLeaf = (root.left is None and root.right is None)
        if isLeaf and target == root.val:
            ret.append(path[:])  # 这里这一步要千万注意啊,
            # 假如是:ret.append(path), 结果是错的。因为Python可变对象都是引用传递啊。
 
        #print "target:", target, "isLeaf:", isLeaf,
        #print "val:", root.val, "path:", path, "ret:", ret
        #print
 
        if root.left:
            self.Find(root.left, target - root.val, ret, path)
        if root.right:
            self.Find(root.right, target - root.val, ret, path)
 
        path.pop()

猜你喜欢

转载自blog.csdn.net/qq_24429333/article/details/87882298
今日推荐