二叉树-路径(前序)

Posted naonaoling

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树-路径(前序)相关的知识,希望对你有一定的参考价值。

112. 路径总和

 1 class Solution {
 2     public boolean hasPathSum(TreeNode root, int sum) {
 3         if(root==null){
 4             return false;
 5         }
 6         if(sum==root.val && root.left==null && root.right==null){ //有个叶子结点的约束
 7             return true;
 8         }
 9         return hasPathSum(root.left, sum-root.val) 
10         || hasPathSum(root.right, sum-root.val);
11     }
12 }

113. 路径总和 II    面试题34. 二叉树中和为某一值的路径

 1 class Solution {
 2     public List<List<Integer>> pathSum(TreeNode root, int sum) {
 3         List<List<Integer>> res = new ArrayList<>();
 4         // if(root==null){
 5         //     return res;
 6         // }
 7         findPath(root, sum, new ArrayList<>(), res);
 8         return res;
 9     }
10     public void findPath(TreeNode node, int sum, List<Integer> cur, List<List<Integer>> res){
11         if(node==null){
12             return;
13         }
14         cur.add(node.val);
15         if(node.val==sum && node.left==null && node.right==null){
16             res.add(cur);
17             return;
18         }
19         findPath(node.left, sum-node.val, new ArrayList<>(cur), res);
20         findPath(node.right, sum-node.val, new ArrayList<>(cur), res);
21     }
22 }
 1 class Solution {
 2     public List<List<Integer>> pathSum(TreeNode root, int sum) {
 3         List<List<Integer>> res = new ArrayList<>();
 4         // if(root==null){
 5         //     return res;
 6         // }
 7         findPath(root, sum, new Stack<>(), res);
 8         return res;
 9     }
10     public void findPath(TreeNode node, int sum, Stack<Integer> cur, List<List<Integer>> res){
11         if(node==null){
12             return;
13         }
14         cur.push(node.val);
15         if(node.val==sum && node.left==null && node.right==null){
16             res.add(new ArrayList<>(cur));
17             // return;  //加上return会有问题,会导致这个结点不被pop
18         }
19         // 可以加入左右子是否为空的判断,但加不加都行,反正进到函数里面也会判空
20         findPath(node.left, sum-node.val, cur, res);
21         findPath(node.right, sum-node.val, cur, res);
22         cur.pop();
23     }
24 }

注:思路1比较好想,但是比较费空间;思路2和cousin那道题很像,注意对比理解

(1)找到路径就放入res;否则找左右子,找完左右子,pop出当前结点==>也就是以这个结点为root的子树遍历完了,把这个结点pop,不要占用list。

(2)cousin:找到结点就return,因为路径唯一;否则找左右子,找完左右子也pop当前结点==>也就是以这个结点为root的子树遍历完了。 

 

437. 路径总和 III  ?? 非常容易出错

 1 class Solution {
 2     public int count = 0;  // 常量类型只能提出来,和list不同,因为每次传参都不一是一个对象
 3     public int pathSum(TreeNode root, int sum) {
 4         if(root==null){
 5             return count;
 6         }
 7         findPath(root, sum);
 8         pathSum(root.left, sum);
 9         pathSum(root.right, sum);
10         return count;
11     }
12     public void findPath(TreeNode node, int cur){
13         if(node==null){
14             return;
15         }
16         if(node.val == cur){
17             count+=1;
18         }
19         findPath(node.left, cur-node.val); 
20         findPath(node.right, cur-node.val);
21     }
22 }

理解:

pathSum:以当前结点作为起始结点找路径;并且分别把左右子结点作为根,计算子树的路径。---因为题目要求起始结点不一定是root

findPath:单纯找路径。

下面是错误解法,很容易陷入重复调用:

 1 class Solution {
 2     public int count = 0;  // 常量类型只能提出来,和list不同,因为每次传参都不一是一个对象
 3     public int pathSum(TreeNode root, int sum) {
 4         findPath(root, sum, sum);
 5         return count;
 6     }
 7     public void findPath(TreeNode node, int cur, int sum){
 8         if(node==null){
 9             return;
10         }
11         if(node.val == cur){
12             count+=1;
13         }
14         findPath(node.left, cur-node.val, sum);  //(1)
15         findPath(node.right, cur-node.val, sum);
16         findPath(node.left, sum, sum);   // (2)
17         findPath(node.right, sum, sum);
18     }
19 

技术图片

993. 二叉树的堂兄弟节点

 1 class Solution {
 2     public boolean isCousins(TreeNode root, int x, int y) {
 3         if(root==null){
 4             return false;
 5         }
 6         Stack<Integer> stack1 = new Stack<>();
 7         Stack<Integer> stack2 = new Stack<>();
 8         findPath(root, x, stack1);
 9         findPath(root, y, stack2);
10         stack1.pop();
11         stack2.pop();
12         return stack1.size()==stack2.size() && stack1.pop()!=stack2.pop();
13     }
14     public boolean findPath(TreeNode node, int val, Stack<Integer> stack){
15         if(node==null){
16             return false;
17         }
18         stack.push(node.val);
19         if(node.val == val){
20             return true;
21         }else{
22             if(findPath(node.left, val, stack)){
23                 return true;
24             }
25             if(findPath(node.right, val, stack)){
26                 return true;
27             }
28             stack.pop();  // 注意
29             return false;
30         }
31     }
32 }

注:这道题本质就是一个查找路径问题,利用递归的思想查找路径。还有另一种解法,用两个map分别存储结点的父结点和层数,之后做对比,这种解法时间复杂度和空间复杂度都更小,因为是查一遍。但是第一种解法感觉更具普适性,保存路径的操作很多题都会用到。

 1 class Solution {
 2     public boolean isCousins(TreeNode root, int x, int y) {
 3         if(root==null){
 4             return false;
 5         }
 6         Map<Integer,TreeNode> father = new HashMap<>();
 7         Map<Integer,Integer> layer = new HashMap<>();
 8         Stack<Integer> stack2 = new Stack<>();
 9         findNode(root, null, father, layer);
10         return layer.get(x)==layer.get(y) && !father.get(x).equals(father.get(y));
11     }
12     public void findNode(TreeNode node, TreeNode par, Map<Integer,TreeNode> father, Map<Integer,Integer> layer){
13         if(node==null){
14             return;
15         }
16         int lay = par != null ? 1 + layer.get(par.val) : 0;
17         father.put(node.val, par);
18         layer.put(node.val, lay);
19         findNode(node.left, node, father, layer);
20         findNode(node.right, node, father, layer);
21     }
22 }

也可以把两个map定义为类成员变量,省的传来传去;father也可以用只保存val,都行。

面试题 04.08. 首个共同祖先

687. 最长同值路径

 

以上是关于二叉树-路径(前序)的主要内容,如果未能解决你的问题,请参考以下文章

二叉树:找我的所有路径?

面试---算法面试

二叉树中,啥是前序,中序。后序!

二叉树面试题刷题模板(终极版)

二叉树的前序中序后序层次遍历的原理及C++代码实现

144_二叉树的前序遍历