【寸铁的刷题笔记】树、dfs、bfs、回溯、递归(一)

news2024/11/15 6:48:05

【寸铁的刷题笔记】树、dfs、bfs、回溯、递归(一)

大家好 我是寸铁👊
总结了一篇刷题关于树、dfs、bfs、回溯、递归的文章✨
喜欢的小伙伴可以点点关注 💝


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

模拟分析图

在这里插入图片描述

代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTree1(preorder , 0 , preorder.length , inorder , 0 , inorder.length);
    }
    public TreeNode buildTree1(int []preorder , int preLeft, int preRight , int []inorder , int inLeft , int inRight){
        //递归终止条件
        //中序数组中右边界-左边界 < 1
        //返回null
       if(inRight - inLeft < 1){
           return null;
       }
       //只有一个节点
       //则创建该值的节点返回出去即可
       if(inRight - inLeft == 1){
           return  new TreeNode(inorder[inLeft]);
       }

        //前序遍历中的第一个值为根节点的值
        int Val = preorder[preLeft];

        //记录根节点的下标索引
        int rootIdx = 0;

        //在中序数组中查找到第一个值所在的下标
        //用于根据该下标进行数组的切割
        TreeNode root = new TreeNode(Val);
        for(int i = inLeft; i < inRight; i++){
            if(inorder[i] == Val){
                rootIdx = i;
                break;
            }
        }

        //递归根节点的左子树和右子树
        //注意: 编写递归时要统一规范
        //由于上面写的是i < inRight
        //这里需要不断查找每个切分的数组的根节点进行切割。
        //区间是左闭右开的 要统一规范去写
        //清楚是左闭右开后 编写逻辑如下:
        root.left = buildTree1(preorder , preLeft + 1 , preLeft + 1 + (rootIdx - inLeft) , inorder , inLeft , rootIdx);
        root.right = buildTree1(preorder , preLeft+1+(rootIdx - inLeft) , preRight , inorder , rootIdx + 1 , inRight);

        //返回最后的根节点
        //每次递归时,向上返回该节点,接住该节点的是左孩子或者右孩子
        return root;
    }
}




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

模拟分析图

在这里插入图片描述

代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        //注:传入的是中序和后序数组的长度
        //区间是左闭右开
        return buildTree1(inorder , 0 , inorder.length , postorder , 0 , postorder.length);
    }
    public TreeNode buildTree1(int []inorder , int inleft, int inRight , int[]postorder , int postLeft,int postRight){
        //对中序数组进行判断
        //如果说中序数组的长度 - 起点下标 < 1 
        //则说明没有元素 返回空
        // 0 - 0 = 0 < 1
         if(inRight - inleft < 1){
            return null;
        }
        //只有一个元素
        //则创建一个该元素的节点返回即可
        if(inRight - inleft == 1){
            return new TreeNode(inorder[inleft]);
        }
        //后序数组中的最后一个元素即为根起点
        int rootVal = postorder[postRight - 1];
        TreeNode root = new TreeNode(rootVal);
       
        int rootIndex = 0;
         //根据拿到的根节点root在中序数组中找到切割点
        for(int i = inleft; i < inRight; i++){
            if(inorder[i] == rootVal){
                rootIndex = i;
            }
        }
        //根据rootIndex在中、后序数组中划分左右子树
        //在中序中划分
        root.left = buildTree1(inorder , inleft , rootIndex, 
                postorder , postLeft , postLeft + (rootIndex - inleft));
        //在后序中划分        
        root.right = buildTree1(inorder, rootIndex + 1, inRight , postorder , postLeft + (rootIndex - inleft) , postRight - 1);        
        return root;
    }
}

112. 路径总和

代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        //如果说根节点为空 则无法得到目标和 直接返回false
        if(root == null) return false;
        //采用的是减法 看最后targetSum 减少到最后是否为0
        //递归调用 传入根节点 此时count和为targetSum - 当前根节点的值
        return traversal(root , targetSum - root.val);
    }
    public boolean traversal(TreeNode cur , int count){
        //如果说左子树和右子树都为空(此为叶子节点) 并且count等于0
        //则说明存在路径使得节点之和为targetSum
        //返回true
        if(cur.left == null && cur.right == null && count == 0)return true;
        //否则返回false
        if(cur.left == null && cur.right == null && count == 0)return false;
        //递归逻辑
        //递归左子树
        if(cur.left != null){
            //减去当前遍历到的节点值
            count -= cur.left.val;
            //注意:这里需要向上返回布尔值
            //如果往左子树遍历的结果为true
            //则向上返回true
            if(traversal(cur.left , count)){
                return true;
            }
            //回溯 把之前减去的节点值加上
            //再从另一个分支去寻找是否存在路径
            count += cur.left.val;
        }
        //同理,递归右子树
        if(cur.right != null){
            count -= cur.right.val;
            if(traversal(cur.right , count)){
                return true;
            }
            count += cur.right.val;
        }
        return false;
    }
}



113. 路径总和 II

相比较 112. 路径总和
113. 路径总和 II || 与下面的 129. 求根节点到叶节点数字之和
共同的逻辑都是需要遍历一棵树从根节点到所有叶子节点
这意味着需要一个数据结构(list)去存储所有经过的路径上的节点
也就意味着不需要返回值,但是由于需要遍历所有的叶子节点
这里需要进行向上回溯,也就是怎么来的就怎么去(恢复现场)

代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    //result队列用于接收满足条件的path
    List<List<Integer>> result;
    //path用于接收每次搜索的结果
    //这里不用开启全局变量
    //原因:path会遍历到叶子节点会向上回溯 
    LinkedList<Integer> path;
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
      result = new LinkedList<>();
      path = new LinkedList<>();
      travesal(root , targetSum);
      return result;
    }
    //这里由于有path接收搜索的结点
    //所以,这里不需要去返回值
    public void travesal(TreeNode root , int count){
        //如果说根节点为空 则直接结束
        if(root == null) return;
        //先把当前的节点值加入到path队列中
        path.offer(root.val);
        //然后,更新当前的count 把当前添加入队列的节点值减去
        count -= root.val;
        //接着,处理临界条件,也就是遍历到叶子节点对答案的判断
        if(root.left == null && root.right == null && count == 0){
            //满足条件则把当前遍历的节点添加到path队列中
            result.add(new LinkedList<>(path));
        }
        //向下递归,遍历左子树和右子树
        //这里是直接往左子树或者右子树的某个方向能走的路走到底
        //无论是往右还是左走 走到底即可
        //走到底无路可走后再向上回溯 依次移除最后一个元素 再去搜索其他分支
        travesal(root.left , count);
        travesal(root.right , count);
        path.removeLast();
    }
}

debug

class Solution {
    List<List<Integer>> result;
    LinkedList <Integer> path;
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        result = new LinkedList<>();
        path = new LinkedList<>();
        travesal(root , targetSum);
        return result;
    }
    public void travesal(TreeNode root , int count){
        if(root == null)return;
        path.offer(root.val);
        count -= root.val;
          System.out.println("111111111");
         System.out.println(path);
        if(root.left == null && root.right == null && count == 0){
            //打印出来去看path的变化过程
             System.out.println("22222222");
            System.out.println(path);
            result.add(new LinkedList<>(path));
        }
        travesal(root.left , count);
        System.out.println("leftleftleftleftleftleft");
        System.out.println(path);
        travesal(root.right , count);
        System.out.println("333333333333");
        System.out.println(path);
        
        //依次移除掉最后一个节点,向上回溯
        //直至移除到最后一个根节点
        path.removeLast();
    }
}

129. 求根节点到叶节点数字之和

代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    //path存储dfs到的节点
    List<Integer>path = new LinkedList<>();
   //记录最终求和的结果
    int res = 0;
    public int sumNumbers(TreeNode root) {
        //如果root为null 则返回0
        if(root == null)return 0;
        //如果root不为null 则把根节点添加到path中
        path.add(root.val);
        travesal(root);
        return res;
    }
    public void travesal(TreeNode root){
        //遍历到叶子节点则对当前的path的值求和
        if(root.left == null && root.right == null){
            res += listToInt(path);
        }
        //遍历左子树
        if(root.left != null){
            //先添加左子树节点的值
            path.add(root.left.val);
            //再继续递归到下一层
            travesal(root.left);
            //移除掉当前队列中的最后一个元素 向上回溯
            path.remove(path.size() - 1);
        }
        //遍历右子树
        if(root.right != null){
            path.add(root.right.val);
            travesal(root.right);
            path.remove(path.size() - 1);
        }
    }
    //对path中存储的节点值进行求和
    public int listToInt(List<Integer> path){
        int sum = 0;
        //这里由于list是队列 先进先出
        //在原来的sum基础上乘10 再加上最后一个元素即可
        for(Integer s : path){
            sum = sum * 10 + s;
        }
        return sum;
    }
    
}

总结

大逻辑其实还是最核心的三个点,一个是根节点,一个是左孩子 ,一个是右孩子
可以把递归函数看成是一个整体部分,整体的去对左子树进行处理,整体
的去对右子树进行处理,然后返回结果或者说记录结果,不必去深究递归里面的细节,会让整个的解题思路变得十分复制混乱,就是理解为递归函数去帮助你进行处理,最后返回一个结果或者将结果存起来就好了!


看到这里的小伙伴,恭喜你又掌握了一个技能👊
希望大家能取得胜利,坚持就是胜利💪
我是寸铁!我们下期再见💕


往期好文💕

保姆级教程

【保姆级教程】Windows11下go-zero的etcd安装与初步使用

【保姆级教程】Windows11安装go-zero代码生成工具goctl、protoc、go-zero

【Go-Zero】手把手带你在goland中创建api文件并设置高亮


报错解决

【Go-Zero】Error: user.api 27:9 syntax error: expected ‘:‘ | ‘IDENT‘ | ‘INT‘, got ‘(‘ 报错解决方案及api路由注意事项

【Go-Zero】Error: only one service expected goctl一键转换生成rpc服务错误解决方案

【Go-Zero】【error】 failed to initialize database, got error Error 1045 (28000):报错解决方案

【Go-Zero】Error 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)报错解决方案

【Go-Zero】type mismatch for field “Auth.AccessSecret“, expect “string“, actual “number“报错解决方案

【Go-Zero】Error: user.api 30:2 syntax error: expected ‘)‘ | ‘KEY‘, got ‘IDENT‘报错解决方案

【Go-Zero】Windows启动rpc服务报错panic:context deadline exceeded解决方案


Go面试向

【Go面试向】defer与time.sleep初探

【Go面试向】defer与return的执行顺序初探

【Go面试向】Go程序的执行顺序

【Go面试向】rune和byte类型的认识与使用

【Go面试向】实现map稳定的有序遍历的方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1464540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android中Transition过渡动画的简单使用

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂&#xff0c;风趣幽默"&#xff0c;感觉非常有意思,忍不住分享一下给大家。 &#x1f449;点击跳转到教程 一、布局xml文件代码如下&#xff1a; <?xml version"1.0" encoding&quo…

websocket与Socket的区别

概念讲解 网络&#xff1a;通俗意义上&#xff0c;也就是连接两台计算器 五层网络模型&#xff1a;应用层、传输层、网络层、数据链路层、物理层 应用层 (application layer)&#xff1a;直接为应用进程提供服务。应用层协议定义的是应用进程间通讯和交互的规则&#xff0c;不…

【结合OpenAI官方文档】解决Chatgpt的API接口请求速率限制

OpenAI API接口请求速率限制 速率限制以五种方式衡量&#xff1a;RPM&#xff08;每分钟请求数&#xff09;、RPD&#xff08;每天请求数&#xff09;、TPM&#xff08;每分钟令牌数&#xff09;、TPD&#xff08;每天令牌数&#xff09;和IPM&#xff08;每分钟图像数&#x…

网页403错误(Spring Security报异常 Encoded password does not look like BCrypt)

这个错误通常表现为"403 Forbidden"或"HTTP Status 403"&#xff0c;它指的是访问资源被服务器理解但拒绝授权。换句话说&#xff0c;服务器可以理解你请求看到的页面&#xff0c;但它拒绝给你权限。 也就是说很可能测试给定的参数有问题&#xff0c;后端…

【rust】vscode下rust-analyzer和Rust Test Lens的Lens

背景 一个粉丝问&#xff1a; 我编辑的launch.json为什么只在按F5的时候工作 按这个debug按钮就不工作&#xff1f; 那在哪改这个插件的配置文档&#xff1f;我一直用的F5 今天上午才注意到这个问题&#xff0c;比如怎么改程序的命令行参数&#xff0c;我意思是如果我非要用…

如何使用逻辑回归处理多标签问题?

逻辑回归处理多分类 1、背景描述2、One vs One 1、背景描述 逻辑回归本身只能用于二分类问题&#xff0c;如果实际情况是多分类的&#xff0c;那么就需要对模型进行一些改动。下面介绍三种常用的将逻辑回归用于多分类的方法 2、One vs One OvO&#xff08;One vs One&#xff…

【嵌入式学习】QT-Day3-Qt基础

1> 思维导图 https://lingjun.life/wiki/EmbeddedNote/20QT 2> 完善登录界面 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后…

igolang学习3,golang 项目中配置gin的web框架

1.go 初始化 mod文件 go mod init gin-ranking 2.gin的crm框架 go get -u github.com/gin-gonic/gin 3.go.mod爆红解决

C2-1.4(L1,L2)正则化

C2-1.4&#xff08;L1,L2&#xff09;正则化 参考书籍 1 正则化的概念 正则化(Regularization) 是机器学习中对原始损失函数引入额外信息&#xff0c;以便防止过拟合和提高模型泛化性能的一类方法的统称。也就是目标函数变成了原始损失函数额外项&#xff0c;常用的额外项一般…

Oladance、南卡、韶音开放式耳机怎么样?3个月真实对比测评

​哪款开放式耳机好用&#xff1f;我亲自体验并评测了市场上流行的三个品牌的开放式耳机&#xff1a;Oladance、南卡、韶音。通过深入测试多维度性能表现&#xff0c;确保你能够远离劣质产品可能带来的问题。我想提醒大家&#xff0c;如果选错耳机可能会影响到音乐的真实还原和…

【高德地图】Android搭建3D高德地图详细教

&#x1f4d6;Android搭建3D高德地图详细教程 &#x1f4d6;第1章 高德地图介绍✅了解高德地图✅2D地图与3D地图 &#x1f4d6;第2章 搭建3D地图并显示✅第 1 步&#xff1a;创建 Android 项目✅第 2 步&#xff1a;获取高德Key✅第 3 步&#xff1a;下载地图SDK✅第 4 步&…

2023 龙蜥操作系统大会演讲实录:《兼容龙蜥的云原生大模型数据计算系统——πDataCS》

本文主要分三部分内容&#xff1a;第一部分介绍拓数派公司&#xff0c;第二部分介绍 πDataCS 产品&#xff0c;最后介绍 πDataCS 与龙蜥在生态上的合作。 杭州拓数派科技发展有限公司&#xff08;简称“拓数派”&#xff0c;英文名称“OpenPie”&#xff09;是国内基础数据计…

Android platform tool中d8.bat不生效

d8.bat因找不到java_exe文件&#xff0c;触发EOF d8.bat中之前代码为&#xff1a; set java_exe if exist "%~dp0..\tools\lib\find_java.bat" call "%~dp0..\tools\lib\find_java.bat" if exist "%~dp0..\..\tools\lib\find_java.bat" …

【教3妹学编程-算法题】匹配模式数组的子数组数目 II

3妹&#xff1a;2哥2哥&#xff0c;你有没有看到上海女老师出轨男学生的瓜啊。 2哥 : 看到 了&#xff0c;真的是太毁三观了&#xff01; 3妹&#xff1a;是啊&#xff0c; 老师本是教书育人的职业&#xff0c;明确规定不能和学生谈恋爱啊&#xff0c;更何况是出轨。 2哥 : 是啊…

petalinux_zynq7 驱动DAC以及ADC模块之一:建立IP

0. 环境 - ubuntu18 - vivado 2018.3 - mizar z7010 ada106模块 1. vivado 1.1 创建vivado工程 运行vivado source /tools/Xilinx/Vivado/2018.3/settings64.sh vivado& 创建vivado工程 Vivado -> Create Project -> Next -> -> Project name: …

【论文阅读笔记】Revisiting RCAN: Improved Training for Image Super-Resolution

论文地址&#xff1a;https://arxiv.org/abs/2201.11279 代码地址&#xff1a;https://github.com/zudi-lin/rcan-it 论文小结 本文的工作&#xff0c;就是重新审视之前的RCAN&#xff0c;然后做实验来规范化SR任务的训练流程。 此外&#xff0c;作者得出一个结论&#xff1a;…

Vue单文件学习项目综合案例Demo,黑马vue教程

文章目录 前言一、小黑记事本二、购物车三、小黑记账清单 前言 bilibili视频地址 一、小黑记事本 效果图 主代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"/><meta http-equiv"X-UA-Compatible&…

linux增加物理磁盘并挂载到文件系统

centos7增加物理磁盘并挂载到文件系统 1、查看所有磁盘情况 fdisk -l2、创建挂载路径 mkdir /data3、格式化磁盘 #磁盘filesystem(上图标红处) mkfs.xfs -f /dev/sda建议 与其它磁盘文件系统保持一致&#xff0c;我这里是xfs 可通过 cat /dev/sda查看 4、挂载 mount /dev/…

5个精美的wordpress中文企业主题模板

元宇宙WordPress主题模板 简洁大气的元宇宙 Metaverse WordPress主题模板&#xff0c;适合元宇宙行业的企业官网使用。 https://www.jianzhanpress.com/?p3292 职业技术培训WordPress主题模板 简洁大气的职业技术培训WordPress主题&#xff0c;适合用于搭建教育培训公司官方…

3个wordpress中文企业主题模板

农业畜牧养殖wordpress主题 简洁大气的农业畜牧养殖wordpress主题&#xff0c;农业农村现代化&#xff0c;离不开新农人、新技术。 https://www.jianzhanpress.com/?p3051 老年公寓wordpress主题 浅绿色简洁实用的老年公寓wordpress主题&#xff0c;适合做养老业务的老年公…