二叉树中和为某一值的路径(一)(二)(三)(剑指offer)

简介: 二叉树中和为某一值的路径(一)(二)(三)(剑指offer)

二叉树中和为某一值的路径(一)

image.png

image.png

//方法一:递归前序遍历
    public boolean hasPathSum (TreeNode root, int sum) {
        //路径不存在,出口!
         if(root==null) return false;
          //处理当前节点!
         sum-=root.val;//更新值!
        if(sum==0&&root.left==null&&root.right==null)
            return true;
        //遍历左右子树
        return hasPathSum(root.left,sum)||hasPathSum(root.right,sum);
    }
//层序遍历(关键每一层中的节点有不同的路径和,所以构造了一个内部类记录不同节点的路径和)
//内部类和路径相关联!
,    class Pair{
        TreeNode curNode =null;
        int curVal = 0;//记录当前路径和!
        public Pair(TreeNode curNode,int curVal){
            this.curNode = curNode;
            this.curVal = curVal;
        }
    }
    public boolean hasPathSum (TreeNode root, int sum) {
        // write code here
        //方法二:层序遍历
        //借助队列!
        if(root==null) return false;
        Queue<Pair> queue = new LinkedList<>();
        queue.offer(new Pair(root,root.val));
        while(!queue.isEmpty()){
                Pair cur = queue.poll();
                if(cur.curNode.left!=null){//左节点入队
                    queue.offer(new Pair(cur.curNode.left,cur.curVal+cur.curNode.left.val));
                }
                if(cur.curNode.right!=null){//右节点入队
                    queue.offer(new Pair(cur.curNode.right,cur.curVal+cur.curNode.right.val));
                }
                if(sum==cur.curVal&&cur.curNode.right==null&&cur.curNode.left==null){
                    return true;
                }
        }
        return false;
    }

image.png


//非递归  
public boolean hasPathSum (TreeNode root, int sum) {
        // write code here
        //利用两个栈,一个栈存当前路径和,一个用于深度优先遍历!
        if(root==null) return false;
        Stack<TreeNode> stack1 = new Stack<>();
        stack1.add(root);
        Stack<Integer> stack2 = new Stack<>();
        stack2.add(root.val);
        while(!stack1.isEmpty()){
            TreeNode cur = stack1.pop();
            int curVal = stack2.pop();
            if(sum==curVal&&cur.left==null&&cur.right==null){
                return true;
            }
            if(cur.left!=null){
                //将左节点和对应的路径和入栈!
                stack1.push(cur.left);
                stack2.push(curVal+cur.left.val);
            }
             if(cur.right!=null){
                //将右节点和对应的路径和入栈!
                stack1.push(cur.right);
                stack2.push(curVal+cur.right.val);
            }
        }
        return false;
    }

这里采用两个栈,一个用于存节点,一个用于存对应路径和, 和刚刚通过层序遍历用Pair保存当前路径和作用类似!

二叉树中和为某一值的路径(二)

题目链接


描述:


image.png

image.png

这题和1一样,这里只不过需要借助数组集合保存结果集即可!


//回溯!
public class Solution {
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int expectNumber) {
       //这里采用回溯,深度优先遍历!
        //关键就是当访问某一子树后,回到该处时需要将该节点除去!
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        if(root==null) return result;
        ArrayList<Integer> tmp = new ArrayList<>();
        FindPathHelp(root,expectNumber,0,result,tmp);
        return result;
    }
    public void FindPathHelp(TreeNode root,int expectNumber,int sum,ArrayList<ArrayList<Integer>> result,ArrayList<Integer> tmp){
        //出口,返回!
        if(root==null){//不满足,回退到上一层
            return;
        }
        //处理这一节点!
        tmp.add(root.val);
        sum += root.val;
        //检查是否满足条件!
        if(sum==expectNumber&&root.left==null&&root.right==null){
            result.add(new ArrayList<>(tmp));
            tmp.remove(tmp.size()-1);//tmp.remove ,return 二选一!
            return;
        }
        //处理下一层
        FindPathHelp(root.left,expectNumber,sum,result,tmp);
        FindPathHelp(root.right,expectNumber,sum,result,tmp);
        //回退!
        tmp.remove(tmp.size()-1);
        return;
    }
}

注意:


这里本层结果的判断不能在其左右节点判断

if(sum==expectNumber&&root==null)这样结果会重复添加2次!


image.png


如图就是一整个回溯的过程!


二叉树中和为某一值的路径(三)

题目链接

image.png



我们这里遇到的问题就是需要确定路径的开始位置根!

如果根确定了就转化成了上面的问题,所以我们可以通过递归来进行遍历根,达到路径起点不同的效果!

所以这里的一层递归,加上上述递归!就通过两层递归解决了这个问题!

//两层递归! 
private int ret = 0;
    private void dfs(TreeNode root,int sum){
        if(root==null) return;
        sum -= root.val;
        if(sum==0) ret++;
        dfs(root.left,sum);
        dfs(root.right,sum);
        sum +=root.val;
        return;
    }
    public int FindPath (TreeNode root, int sum) {
        // write code here
        //二叉递归
        //一次递归根节点,第二次判断以该根节点为起始节点是否有匹配路径!
        //递归遍历该树,前序遍历避免了回溯了
        if(root==null) return ret;
        //计算该根起始匹配路径!
         dfs(root,sum);
        //遍历左右!
         FindPath(root.left,sum);
         FindPath(root.right,sum);
        return ret;
    }

时间复杂度:O(n^2)两层递归!

空间复杂度:O(n)每层递归最深就只有n

我们也可以通过递归+哈希解决这个问题!


我们这里最重要的就是实现路径起始节点的移动!


我们可以通过哈希表保存每条路径和出现的次数!


如果当到达一个节点后, 该节点位置的值加上上一层的路径和 - sum的值在hash表中,说明前面位置的位置的值可以用这个节点值代替,所以将hash表中的这个路径出现次数加在 res中!


这个方法不太好理解…

image.png

private HashMap<Integer,Integer> mp = new HashMap<>();
    //上层路径和:last
    public int dfs(TreeNode root,int sum, int last){
        if(root==null) return 0;
        int res = 0;
        //到该节点路径和!
        int tmp = root.val + last; 
        //如果该路径和减去sum在哈希表中出现过,想当于减支!
        //也就是这个节点的效果等同于上面路径的某和,所以就需要下移,去掉前面的!
        if(mp.containsKey(tmp - sum)){
            //加上这个路径和出现的次数!
            res +=mp.get(tmp - sum);
        }
        //增加该路径和
        mp.put(tmp,mp.getOrDefault(tmp,0)+1);
        res += dfs(root.left,sum,tmp);
        res += dfs(root.right,sum,tmp);
        //回退!
        mp.put(tmp,mp.get(tmp)-1);
        return res;
    }
    public int FindPath (TreeNode root, int sum) {
        // write code here
        mp.put(0,1);
        return dfs(root,sum,0);
    }

时间复杂度:O(n),其中n为二叉树的结点数,遍历一次二叉树,哈希表的操作都是O(1)

空间复杂度:O(n),哈希表大小及递归栈最大为n

目录
相关文章
|
JavaScript 搜索推荐 前端开发
WordPress主题推荐
作为网站的基础,WordPress主题对网站加载速度具有重要影响。一个设计不好,代码杂乱的WordPress主题会严重影响网站加载速度,进而影响网站排名。相反,一个设计良好,代码简洁的WP主题会加载很快,有助于提升网页排名。如果你想创建一个精美的WordPress网站,选择一个优秀的主题至关重要。然而,在追求美观的同时,绝不能忽视性能和速度。在本文中,我们已经为你整理了一些速度快且适合SEO的WordPress主题。
414 4
WordPress主题推荐
|
传感器 人工智能 物联网
带你了解热门IoT开源项目:home assistant
home assistant是一个基于python的家庭智能化平台,可运行于本地服务器,或者树莓派上。利用该平台,可以统一控制家庭中所有的智能设备。
带你了解热门IoT开源项目:home assistant
|
搜索推荐 API 开发工具
打造个性化天气应用:从零开始的iOS开发之旅
【8月更文挑战第31天】本文是一篇针对初学者的iOS应用开发指南,将引导读者通过Swift和iOS SDK构建一个简单而美观的天气应用。我们将探索如何利用API获取实时天气数据,并在应用中实现用户友好的界面设计。文章不仅包括代码示例,还提供了设计理念和用户体验优化的建议,旨在帮助初学者理解iOS开发的基础知识,并激发他们创造个性化应用的兴趣。
|
11月前
|
存储 C语言
【C语言】typedef 关键字详解
`typedef` 关键字在C语言中用于定义现有数据类型的别名,提高代码的可读性和可维护性。它常用于简化复杂数据类型、定义函数指针类型以及处理联合体和枚举类型。掌握 `typedef` 的用法可以使你的代码更加清晰和易于管理。
571 1
|
存储 Unix 数据挖掘
服务器数据恢复—SAN环境下LUN Mapping出错导致文件系统共享冲突的数据恢复案例
服务器数据恢复环境: SAN环境下一台存储设备中有一组由6块硬盘组建的RAID6磁盘阵列,划分若干LUN,MAP到不同业务的SOLARIS操作系统服务器上。 服务器故障: 用户新增了一台服务器,将存储中的某个LUN映射到新增加的这台服务器上。这个映射的LUN其实之前已经MAP到其他SOLARIS操作系统的服务器上了。由于没有及时发现问题,新增加的这台服务器已经对此LUN做了初始化操作,磁盘报错,重启后发现卷无法挂载。
|
存储 传感器 数据安全/隐私保护
CVPR 2024 Highlight:基于单曝光压缩成像,不依赖生成模型也能从单张图像中重建三维场景
【5月更文挑战第15天】CVPR 2024会议上,清华大学研究人员提出的SCINeRF利用单曝光压缩成像(SCI)技术结合神经辐射场(NeRF)进行3D场景重建。SCI以低成本捕捉高维数据,而SCINeRF将SCI的成像过程融入NeRF训练,实现复杂场景的高效重建。实验显示,该方法在图像重建和多视角图像生成方面取得优越性能,但实际应用仍需解决SCI系统设计、训练效率和模型泛化等挑战。[Link: https://arxiv.org/abs/2403.20018]
346 2
|
机器学习/深度学习 自然语言处理 API
使用 Python 集成 ChatGPT API
使用 Python 集成 ChatGPT API
787 1
|
Python
力扣随机一题 模拟+字符串
力扣随机一题 模拟+字符串
96 0
|
人工智能 Python
huggingface_hub加速
huggingface_hub加速
692 0
|
XML JavaScript Java
掌握XML解析:深入比较Java中的四种解析方式
掌握XML解析:深入比较Java中的四种解析方式
496 0
下一篇
开通oss服务