Leetcode 刷题记录 12 —— 二叉树第三弹

用WorkBuddy搭建漫剧AI自动化制作流水线全攻略 在内容创作领域,AI智能体正逐渐从单一工具辅助走向全流程自动化调度。其核心原理是将剧本、分镜、绘图、配音、剪辑等环节拆解为可独立执行的任务单元,由总控系统统一协调,从而大幅降低人力与时间成本。这种模式尤其适用于动态漫画(漫剧)这类环节多、专业度要求高的视频形态。传统制作流程中,角色一致性、配音周期和剪辑返工是公认的效率瓶颈,而借助AI智能体工作台,创作者只需输入故事创意,即可驱动多个数字分身协同完成内容生产。本文以WorkBuddy为例,详细展示如何配置模型、安装技能包并串联五段式流水线,将单集制作成本从万 阅读详情

本系列为笔者的 Leetcode 刷题记录,顺序为 Hot 100 题官方顺序,根据标签命名,记录笔者总结的做题思路,附部分代码解释和疑问解答,01~07为C++语言,08及以后为Java语言。

01 二叉树展开为链表

在这里插入图片描述

在这里插入图片描述

/**
 * 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 void flatten(TreeNode root) {
        
    }
}

方法一:递归

class Solution {
    public void flatten(TreeNode root) {
        List<TreeNode> list = new ArrayList<>();
        preOrder(root, list);

        //⭐
        int size = list.size();
        for(int i=1; i<size; i++){
            TreeNode prev = list.get(i-1);
            TreeNode curr = list.get(i);

            prev.left = null;
            prev.right = curr;
        }
    }

    public void preOrder(TreeNode root, List<TreeNode> list){
        if(root == null){
            return;
        }

        list.add(root);
        preOrder(root.left, list);
        preOrder(root.right, list);
    }
}

方法二:栈

class Solution {
    public void flatten(TreeNode root) {
        List<TreeNode> list = new ArrayList<>();
        Deque<TreeNode> stack = new LinkedList<>();

        while(root != null || !stack.isEmpty()){
            while(root != null){
                list.add(root);
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            root = root.right;
        }

        //⭐
        int size = list.size();
        for(int i=1; i<size; i++){
            TreeNode prev = list.get(i-1);
            TreeNode curr = list.get(i);

            prev.left = null;
            prev.right = curr;
        }
    }
}

方法三:改良版栈

class Solution {
    public void flatten(TreeNode root) {
        if(root == null){
            return;
        }

        Deque<TreeNode> stack = new LinkedList<>();
        stack.push(root);
        TreeNode prev = null;

        while(!stack.isEmpty()){
            TreeNode curr = stack.pop();

            if(prev != null){
                prev.left = null;
                prev.right = curr;
            }

            TreeNode left = curr.left;
            TreeNode right = curr.right;
            if(right != null){
                stack.push(right);
            }
            if(left != null){
                stack.push(left);
            }

            prev = curr;
        }
    }
}

方法四:寻找前驱结点

class Solution {
    public void flatten(TreeNode root) {
        TreeNode curr = root;

        while(curr != null){
            if(curr.left != null){
                TreeNode prev = curr.left;
                while(prev.right != null){
                    prev = prev.right;
                }

                prev.right = curr.right;
                curr.right = curr.left;
                curr.left = null;
            }
            curr = curr.right;
        }
    }
}

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

在这里插入图片描述

在这里插入图片描述

/**
 * 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) {
        
    }
}

方法一:递归

class Solution {
    Map<Integer, Integer> indexMap; //值,下标
    public TreeNode myBuildTree(int[] preorder, int[] inorder, int prel, int prer, int inl, int inr){
        if(prel > prer){
            return null;
        }

        int pre_root = prel; //前序根节点下标
        int in_root = indexMap.get(preorder[prel]); //中序根节点下标

        TreeNode root = new TreeNode(preorder[prel]); //⭐
        int size = in_root - inl;

        root.left = myBuildTree(preorder, inorder, prel+1, prel+size, inl, in_root-1);
        root.right = myBuildTree(preorder, inorder, prel+size+1, prer, in_root+1, inr);

        return root;
    }

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int n = preorder.length;
        indexMap = new HashMap<>();
        for(int i=0; i<n; i++){
            indexMap.put(inorder[i], i);
        }
        return myBuildTree(preorder, inorder, 0, n-1, 0, n-1);
    }
}
问题答案简述
1. 为什么要建立哈希表?为了快速定位根节点在中序数组的位置,避免线性查找,提高时间效率。
2. 为什么 indexMap 要全局定义?递归层层调用都需要访问,定义为全局成员变量方便统一管理,避免反复传参或创建。
3. 为什么比较 prel 和 prer 判断递归结束?递归分割以前序序列区域为准,prel > prer时表示无节点,终止递归更准确。

03 路径总和 Ⅲ

在这里插入图片描述

在这里插入图片描述

/**
 * 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 int pathSum(TreeNode root, int targetSum) {
        
    }
}

方法一:递归

class Solution {
    public int pathSum(TreeNode root, long targetSum) {
        if(root == null){
            return 0;
        }

        int ret = rootSum(root, targetSum);
        ret += pathSum(root.left, targetSum);
        ret += pathSum(root.right, targetSum);

        return ret;
    }

    public int rootSum(TreeNode root, long targetSum){
        if(root == null){
            return 0;
        }

        int ret = 0;
        int val = root.val;
        if(val == targetSum){
            ret++;
        }

        ret += rootSum(root.left, targetSum - val);
        ret += rootSum(root.right, targetSum - val);

        return ret;
    }
}

方法二:前缀和

class Solution {
    public int pathSum(TreeNode root, long targetSum) {
        Map<Long, Integer> prefix = new HashMap<>(); //当前路径总和,出现次数
        prefix.put(0L, 1);

        return dfs(root, prefix, 0, targetSum);
    }

    public int dfs(TreeNode root, Map<Long, Integer> prefix, long curr, long targetSum){
        if(root == null){
            return 0;
        }

        int ret = 0;
        curr += root.val;
        ret = prefix.getOrDefault(curr-targetSum, 0);
        prefix.put(curr, prefix.getOrDefault(curr, 0) + 1); 

        ret += dfs(root.left, prefix, curr, targetSum);
        ret += dfs(root.right, prefix, curr, targetSum);

        prefix.put(curr, prefix.getOrDefault(curr, 0) - 1);

        return ret;
    }
}

① prefix.getOrDefault(curr, 0) 为啥是0啊

  • prefix.getOrDefault(curr, 0) 的作用是取出当前前缀和 curr 在哈希表里出现的次数。
  • 如果这个 curr 第一次出现,prefix 里就没有对应的key,因此用 getOrDefault(curr, 0) 返回默认值0,表示之前没有出现过这个前缀和。

② prefix.put(curr, prefix.get(curr) - 1);为啥呀?

当左、右子树递归完成后,递归函数就要回退到父节点继续处理父节点的其他分支 / 返回父节点。
如果不将当前路径和 curr 的出现次数 -1,那么在返回父节点后,哈希表会错误地保留了当前路径的状态,导致其他路径的统计被污染,出现错误的计数。

③ prefix.put(curr, prefix.getOrDefault(curr, 0) + 1);这里是不断更新吗?

是的,

prefix.put(curr, prefix.getOrDefault(curr, 0) + 1);

这行代码是在递归过程中不断更新当前路径和 curr 出现的次数。

04 二叉树的最近公共祖先

在这里插入图片描述

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        
    }
}

方法一:递归

class Solution {
    private TreeNode ans;
    public Solution(){
        this.ans = null;
    }
    
    //1.创建递归方法dfs
    public boolean dfs(TreeNode root, TreeNode p, TreeNode q){
        if(root == null){
            return false;
        }

        //2.左右孩子结点
        boolean lson = dfs(root.left, p, q);
        boolean rson = dfs(root.right, p, q);

        //⭐
        if((lson && rson) || ((root.val == p.val || root.val == q.val) && (lson || rson))){
            ans = root;
        }

        //3.return包含递归式
        return lson || rson || (root.val == p.val || root.val == q.val);
    }

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        this.dfs(root, p, q);
        return this.ans;
    }
}

① ans 和 dfs 为啥都是 private?

把实现细节隐藏起来,不希望外部代码直接访问递归实现细节和存储结果的变量,避免外部误用或者干扰。ans 是实现变量,dfs 是实现细节的递归函数,外部只需调用公开接口 lowestCommonAncestor。

② 为啥ans一旦赋值,不会改变

dfs 从树的根节点开始,递归访问左右子树后回到根节点。这是一种自底向上的查找方式——当递归顺序回溯到某个节点时,说明这个节点是中间某一层的节点。并且,最近公共祖先是“最低”的公共祖先,即离 p 和 q 最近的那个节点。

05 二叉树中的最大路径和

在这里插入图片描述

在这里插入图片描述

/**
 * 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 int maxPathSum(TreeNode root) {
        
    }
}

方法:递归

class Solution {
    int max = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        myFunction(root);
        return max;
    }

    public int myFunction(TreeNode root){
        if(root == null){
            return 0;
        }

        int L = Math.max(0, myFunction(root.left));
        int R = Math.max(0, myFunction(root.right));

        //⭐
        max = Math.max(max, L + R + root.val);

        return Math.max(L, R) + root.val;
    }
}

万一 root.val 是负的怎么办?

如果 root.val 是负数我们也必须加上它!因为这是这个路径的「根」,路径中必须包含它(因为题目定义路径一定是一个起点到终点连续的节点链),所以这个 L + R + root.val 是整条路径必须包含的值。

Vue3 + uniapp 踩坑:iOS 真机调试一直报错Maximum call stack size exceeded,和(in promise)MiniProgramError err的解决方法 不是你写错代码,是微信开发工具和 iOS 真机调试的兼容问题。开个空项目都报错,勾个设置就没问题,不是你,是工具的锅。 阅读详情

相关推荐

2021年软件测试面试题大全

简述测试流程: 1、阅读相关技术文档(如产品PRD、UI设计、产品流程图等)。 2、参加需求评审会议。 3、根据最终确定的需求文档编写测试计划。 4、编写测试用例(等价类划分法、边界值分析法等)。 5、用例评审(主要参与人员:开发、测试、产品、测试leader)。 6、开发提交代码至SVN或者GIT ,配管搭建测试环境。 7、执行测试用例,记录发现的问题。 8、验证bug与回归测试。 9、编写测试报告。 10、产品上线。 补充测试用例设计过程: 根据需求得出测试需求 设计测试方

hard_days的博客 20万+

Leetcode 刷题记录 11 —— 二叉树第二弹

本系列为笔者的 Leetcode 刷题记录,顺序为 Hot 100 题官方顺序,根据标签命名,记录笔者总结的做题思路,附部分代码解释和疑问解答,01~07为C++语言,08及以后为Java语言。

Celeste的博客 1168

Zynq UltraScale+ MPSoC-AMP(linux+裸机)

接着 Zynq UltraScale+ MPSoC-双核裸机AMP继续 平台工具:zcu106,vitis2020.2,petalinux2019.2 文章目录1.cpu1跑裸机2.cpu0跑linux2.1petalinux设置2.2 app3.生成BOOT.bin4.zcu106测试 1.cpu1跑裸机 参照Zynq UltraScale+ MPSoC-双核裸机AMP建立的工程进行修改。BSP中stdin与out修改为uart1,uart1给裸机用,uart0给linux用。 ddr空间裸机与linu

zhuxl24的博客 5195

Leetcode面试经典150题刷题记录 —— 一维动态规划篇

不记得是在哪里看到过了,某国部队规定,上楼一定要迈两步台阶以彰显阳刚之气,经查阅,我人民解放军队列条例没这个规定,但我估计现实中他们上楼应该是按两步踏的。你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。通过这道题,复习下子序列的定义,和数学中的子数列定义类似。

键盘国治理专家的博客 1360

用LightRAG+Ollama搭建本地知识库:从文档上传到智能问答的完整流程

本文详细介绍了如何利用LightRAG与Ollama构建企业级本地知识库,涵盖从文档预处理到智能问答的完整流程。通过实战案例展示,该方案能高效处理海量文档,实现语义搜索与知识图谱关联分析,显著提升信息检索效率。特别适合金融、医疗等领域的技术团队快速搭建智能知识管理系统。

weixin_42535461的博客 191

LangChain与LangGraph核心区别解析

LangChain与LangGraph是当前大语言模型(LLM)应用开发中两个紧密相关且极具影响力的开源框架。它们源于LangChain AI公司,设计哲学互补,旨在解决不同维度的LLM工程化问题,共同构成了构建复杂智能应用的强大工具集。

weixin_35774598的博客 1915

Leetcode 刷题记录 10 —— 二叉树

本系列为笔者的 Leetcode 刷题记录,顺序为 Hot 100 题官方顺序,根据标签命名,记录笔者总结的做题思路,附部分代码解释和疑问解答,01~07为C++语言,08及以后为Java语言。

Celeste的博客 819

使用MCAL的Fee模块集成ETAS存储协议栈

由于ETAS Fee模块导致初始化时间较长,且集成占用的内存较大,所以最终考虑使用MCAL中的Fee模块来集成ETAS的Nvm模块,本文介绍具体的集成方法注意:本文所涉及的集成前提是原有的ETAS协议栈已正常使用使用IFX Fee需要手动配置Fee,可能有出错的风险,最好是利用脚本自动生成代码来实现。另外,需要注意IFX的Fee中block数据没有CRC校验,如果使用该Fee,建议Nvm中加CRC校验(ETAS Fee中block自带CRC,可以不需要Nvm Crc),防止数据被意外篡改导致的异常。

赞的博客 404

【leetcode刷题记录】(java)二叉树

【leetcode刷题记录】(java)二叉树 刷题参考代码随想录:https://programmercarl.com/

南京大学软件工程硕士在读 1317

【网络安全】Python代码审计高危函数与安全审计建议

Python 灵活且动态的特性使得开发便捷,但同时也带来了严重安全隐患。如果开发者缺乏安全意识,极易引入命令执行、反序列化漏洞及模板注入漏洞。本文总结了 Python 中常见的高危函数、模块和第三方库,并给出对应的审计建议及其原理解析,供安全研究人员和开发者参考。

等风来 416

【个人成长笔记】在Ubuntu中安装RTL8188GU USB无线网卡驱动(Driver for Linux RTL8188GU)

这篇笔记提供了在Ubuntu系统中安装RTL8188GU无线网卡驱动的完整指南。主要内容包括:驱动程序的官方来源(Github链接)、详细安装步骤(通过git下载、编译安装等命令),以及将设备转换为USB网卡模式的关键指令。特别提醒每次开机都需要执行模式转换命令,因为设备默认会以U盘模式启动。文章以简洁的技术文档形式呈现,适合Linux用户快速查阅和操作。

yuhuasheng1997的博客 1826

代码随想录+力扣刷题记录+华为机考准备记录

为了准备华为机考的刷题记录(不全)(已挂,春招再战)为了准备华为机考的刷题记录(不全)(已挂,春招再战)

LiangManqi0320的博客 2342

KEPServerEX 6 之 lot Gateway MQTT Clinet 配置使用方式

IoT Gateway即Internet of Things Gateway物联网网关。 ---------------------------------------------------------------------------------- 方式:使用kepw的IOTGateway插件选择MQTTClient 解决:可以实现 KEPW 的Tag值 发送到 MQTT 服务器上 ----------------------------------------...

-雲飛兄-博客 6942

力扣刷题记录&整理——(七)Trees

整理力扣刷题思路。语言:python题库:来自neetcode:link。

Z_zat的博客 1053

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

刷题记录(力扣热题100)

因为构成单词的字母相同,那么将单词按同一方法排序后产生的序列一定是相同的,那么再进行哈希也一定是相同的,所以我们此时已经确定了第一维的参数,只需将第二维设置为动态数组,然后根据哈希值进行插入即可,最后遍历哈希表将其整合为一个动态数组返回即可。两个指针从两边出发,算一下当前的体积,然后更新较小的那一条边,因为每次更新x轴都会减少,如果更新长边那么体积只会变小,而更新短边才有变大的机会,然后直到两个指针相遇结束,在此期间维护最大面积即可。给定一个数组在不改变其它元素的相对顺序的情况下,将数组中的0移动到末尾。

qq_51676853的博客 2118

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

刷题记录Day15-二叉树(层序遍历、翻转二叉树、对称二叉树)

leetcode代码随想录刷题工具:VSCode+leetcode插件补充:延毕时间充裕,会结合LeetCode 101: A LeetCode Grinding Guide (C++ Version)相似题目一起做。层序遍历都是套模板的题目,虽然ac的很爽,但是还是要加强记忆。二叉树里的递归好烦,我感觉我懂什么意思,但实现的时候又感觉有很多小问题注意不到。

qq_41645729的博客 960

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

wy的leetcode刷题记录_Day87

wy的leetcode刷题记录_Day87声明前言2789. 合并后数组中的最大元素题目介绍思路代码收获54. 螺旋矩阵题目介绍思路代码收获48. 旋转图像题目介绍思路代码收获240. 搜索二维矩阵 II题目介绍思路代码收获226. 翻转二叉树题目介绍思路代码收获101. 对称二叉树题目介绍思路代码收获98. 验证二叉搜索树题目介绍思路代码收获给你一个下标从 0 开始、由正整数组成的数组 nums。

m0_54015435的博客 951

力扣刷题记录_二叉树

记录二叉树各种题型的刷题记录

qq_43563660的博客 562

Leetcode面试经典150题刷题记录 —— 二叉树层次遍历篇

Leetcode面试经典150题刷题记录 —— 二叉树层次遍历篇

键盘国治理专家的博客 1342

力扣简单题刷题记录C++

Leetcode刷题心得

SunLight_z的博客 1198

wy的leetcode刷题记录_Day85

本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间:2024-3-12今天的每日一题是:1261. 在受污染的二叉树中查找元素简单的模拟题,根据题意我们先要将数进行重建这里可以使用BFS或DFS重新建立起完整的树,本来我想的是建立起的树就是二叉搜索树可以直接根据根节点向下遍历,但是我发现题目中的参数并没有跟树有关的的任意节点所以应该是需要额外的空间来记录出现的值,而题中所给出的值也都较为简单可以直接使用数组来解决,但通常应使用哈希表。BFS: DFS: 收获 巩固了BFS和DFS62

m0_54015435的博客 887

刷题记录(代码随想录、力扣hot100)-二叉树(C++实现)

为了记录个人刷题记录,方便最快回忆,只给出二叉树相关题目题意和基本思路,目前包含代码随想录和力扣hot100(C++版本)

m0_51932378的博客 852

【leetcode】二叉树刷题记录(二)

本文是基于leetcode二叉树例题的学习记录。

m0_73389646的博客 776

力扣 Hot 100 刷题记录 - 二叉树的直径

是力扣 Hot 100 中的一道经典题目,题目要求如下:给定一棵二叉树的根节点root,返回这棵树的。二叉树的直径是指树中任意两个节点之间最长路径的长度。这条路径可能经过根节点,也可能不经过。输入:root = [1,2,3,4,5]输出:3输入:root = [1,2]输出:1。

weixin_50893711的博客 952

力扣hot100二刷——二叉树

第二次刷题不在idea写代码,而是直接在leetcode网站上写,“逼”自己掌握常用的函数。

weixin_49426115的博客 1135

wy的leetcode刷题记录_Day90

wy的leetcode刷题记录_Day89声明前言303. 区域和检索 - 数组不可变题目介绍思路代码收获230. 二叉搜索树中第K小的元素题目介绍思路代码收获199. 二叉树的右视图题目介绍思路代码收获114. 二叉树展开为链表题目介绍思路代码收获105. 从前序与中序遍历序列构造二叉树题目介绍思路代码收获计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的 和 ,其中 left

m0_54015435的博客 1108
上一篇: Javase 基础加强 —— 09 IO流第二弹
下一篇: Leetcode 刷题记录 13 —— 图论
东方芷兰
博客等级 码龄5年 426粉丝 108原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值