zoukankan      html  css  js  c++  java
  • 剑指24.二叉树中和为某一值的路径

    题目描述

    输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
     

    思路

           这道题相当于树的DFS。

    1. 遍历方式(根据根节点的位置)由于路径是从根节点出发到叶节点,因此我们首先需要遍历根节点。在树的前中后序遍历中,只有前序遍历是先访问根节点的。

    2. 二叉树遍历过程中没有父节点指针,要保存路径的话,必须要创建容器存储经过的节点。

    3. 回退:在当前结点访问结束后,递归函数将会返回到它的父结点,所以在函数退出之前,要删除链表中的当前结点,以确保返回父结点时,储存的路径刚好是从根结点到父结点。

    ☆☆☆代码实现

    import java.util.ArrayList;
    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
        /* Note:
         * 1. 将 res 和 list定义成全局变量,避免在方法中多次传递
         * 2. 在res添加list时,因为list会不断变化,所以必须新建一个list存入
         *    复制ArrayList的方法:newList=new ArrayList<Integer>(oldList)
         *    (复制内容,而不是复制地址,注意与newList=oldList的区分)
         * 3. 在当前结点完成左右子树的路径搜索后,记得删除list中的当前结点
         * 4. target是基本数据类型int,不会受到方法的影响而改变。
         */
        private ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        private ArrayList<Integer> list = new ArrayList<>();
        public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
            if (root == null) return res;
            list.add(root.val);
            target -= root.val;
            if (target == 0 && root.left == null && root.right == null){ //叶子节点
                int i = 0; // 将长度大的list插入到长度小的list前面
                while (i < res.size() && list.size() < res.get(i).size())
                    i++;
                res.add(i,new ArrayList<>(list));//list会随方法变化,必须新建一个list存入res中!
            }
            // 因为在每一次的递归中,我们使用的是相同的res引用,
            // 所以其实左右子树递归得到的结果我们不需要关心,
            FindPath(root.left,target);
            FindPath(root.right,target);
            list.remove(list.size() - 1); // 记得删除当前节点,深度遍历完一条路径要回退
            return res;
        }
    }

    Q:为什么要写new ArrayList<>(list) 而不能直接写list?

    R1:在链表中存储一个对象时,如果该对象是不断变化的,则应该创建一个新的对象复制该对象的内容(而不是指向同一个对象),将这个新的对象存储到链表中。。如果直接存储该对象的话,链表中的对象也会不断变化。基本数据类型和String则没有这种问题。说到底其实是存储的是地址还是的问题。

    R2:涉及到Java中的 地址传递值传递 ,像List这种数据结构都是传入的地址,而int、String这种都是值,修改后不影响上层的函数。如果直接写list,实际传递的是list原本的地址,这样在递归中list会被修改后返回上层的递归结果,所以需要new一个,递归结束返回上层也不会有影响。

    R3:因为res.add(list)是把list这个对象的引用地址添加到result了,res中的元素就会共用list,而list是我们用来存放当前路径的地方,因此我们需要复制一份之后加入res中。

    如何在本地调试二叉树相关题目?

    1. 在同一个package下新建一个文件“TreeNode.java”

    package com.test;
    
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
        public TreeNode(int val) {
            this.val = val;
        }
    }

    2. 新建另一个文件调试题目

        public static void main(String[] args) {
            TreeNode node_10 = new TreeNode(10);
            TreeNode node_5 = new TreeNode(5);
            TreeNode node_12 = new TreeNode(12);
            TreeNode node_4 = new TreeNode(4);
            TreeNode node_7 = new TreeNode(7);
    
            node_10.left = node_5;
            node_10.right = node_12;
            node_5.left = node_4;
            node_5.right = node_7;
            JZ24 test = new JZ24();
            System.out.println(test.FindPath(node_10, 22));
        }

     
    参考:
     
  • 相关阅读:
    【剑指offer】字符串转整数
    怎样让js不产生冲突,避免全局变量的泛滥,合理运用命名空间
    [每天一个知识点]34-职业生涯-用得着和用不着的知识
    真机iOS SDK升级后xcode不能进行真机调试 怎么办
    SPOJ 11840. Sum of Squares with Segment Tree (线段树,区间更新)
    Atitit.Gui控件and面板----web server区----- web服务器监控面板and控制台条目
    Struts2+Spring+Hibernate step by step 03 整合Spring之中的一个(在DAO层验证username和password)
    WPF中控件ListView和DataGrid典型属性介绍
    leetcode
    layer:好看的弹出窗口
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/13501221.html
Copyright © 2011-2022 走看看