代码随想录算法训练营55期第十六天 | 二叉树part04

OpenCV 算法梳理分析 本文系统梳理了OpenCV的核心算法体系,从模块架构到具体函数实现。OpenCV采用分层设计,包含基础I/O、图像处理、特征检测、视频分析和智能算法五大层次,所有模块基于统一的Mat数据结构。重点分析了imgproc模块的8类图像处理算法(滤波、形态学、阈值化等),features2d模块的特征检测与匹配流程(SIFT/ORB等算法对比),以及objdetect、video、calib3d等模块的核心功能。针对不同场景提供了算法选型建议,如高斯噪声推荐GaussianBlur,特征匹配推荐ORB+Flann 阅读详情

Leetcode 513. 找树左下角的值

思路:这道题要再最后一行 找到最左边的值, 第一反应是用BFS, 遍历每一行都记录第一个值,那么最后一个值就是树左下角的值

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        //bfs
        Queue<TreeNode> queue = new ArrayDeque<>();
        int ans = -1;
        if(root != null){
            queue.offer(root);
        }
        while( !queue.isEmpty()){
            int size = queue.size();
            for (int i = 0; i < size; i++ ){
                TreeNode node = queue.poll();
                if(i == 0){
                    ans = node.val;
                }
                if(node.left != null){
                    queue.offer(node.left);
                }
                if(node.right != null){
                    queue.offer(node.right);
                }
            }
        }
        return ans;
    }
}

使用递归法,在递归过程中要确定深度,并找到最左边的叶子。高度的确定使用一个全局变量,记录最大深度。还需要一个全局变量记录最大深度最左节点的数值。每递归到下一层,最大深度值都会更新,不论使用什么遍历,只要保证先左后右的顺序,第一次更新最大深度时,访问的节点就是该层最左的节点,记录该节点的值。之后虽然会访问同层的其他节点,但是最大深度不再更新,其他节点的值不会被记录。

class Solution {
    int maxDepth = Integer.MIN_VALUE;
    int ans;
    public int findBottomLeftValue(TreeNode root) {
        dfs(root, 0);
        return ans;
    }
    private void dfs(TreeNode root, int depth){
        if(depth > maxDepth){
            maxDepth = depth;
            ans = root.val;
        }
        if(root.left != null){
            dfs(root.left, depth + 1);
        }
        if(root.right != null){
            dfs (root.right, depth + 1);
        }
    }
}

112. 路径总和

112 和113 非常类似,区别在于在遇到leaf 时,进行不同的处理。 递归搭配回溯,比较经典的运用

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root == null) {
            return false;
        }
        if(root.left == null && root.right == null){
            return targetSum == root.val;
        }
        return hasPathSum(root.left, targetSum - root.val) ||
                hasPathSum(root.right, targetSum - root.val);
    }
}

113. 路径总和ii 

class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) return res;
        List<Integer> path = new ArrayList<>();
        dfs(root, targetSum, res, path);
        return res;
    }
    private void dfs(TreeNode root, int targetSum, List<List<Integer>> res, List<Integer> path){
        path.add(root.val);
        if(root.left == null && root.right == null){
            if(targetSum == root.val ){
                res.add(new ArrayList<>(path));
            }
        }
        if(root.left != null){
            dfs(root.left, targetSum - root.val, res, path);
        }
        if(root.right != null){
            dfs(root.right, targetSum - root.val, res, path);
        }
        path.remove(path.size() - 1);
    }
}

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

先用中序和后序数组把二叉树画出来,发现后序数组的最后一个元素是root,通过这个root我们能在中序数组中把左子树和右子树分隔出来,然后用递归处理左子树和右子树。

具体的步骤:

1. 如果数组为空, return null

2. 如果数组不为空,取后序数组最后一个元素为root

3. 以root为切割点,将中序数组分成中序左树数组和中序右树数组

因为数组里元素不重复,所以可以用二分法找到root,或者用HashMap 储存元素和下标,可以以O(1)找到root。

4. 按照中序左树数组和中序右树数组的长度,将后序数组切割

5. 递归处理左数组和右数组


class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        HashMap<Integer, Integer> record = new HashMap<>();
        for(int i = 0; i < inorder.length; i++ ){
            record.put(inorder[i], i);
        }
        return buildTree(inorder, 0, inorder.length -1, postorder, 0, postorder.length - 1, record);
    }

    //左闭右闭
    private TreeNode buildTree(int[] inorder, int inLeft, int inRight,  int[] postorder,int postLeft, int postRight, HashMap<Integer, Integer> record){
        if(inLeft > inRight || postLeft > postRight){
            return null;
        }
        int rootVal = postorder[postRight];
        int idxRoot = record.get(rootVal);
        int leftSize = idxRoot - inLeft;
      
        TreeNode left = buildTree(inorder, inLeft, idxRoot - 1,postorder, postLeft, postLeft + leftSize - 1,record);
        TreeNode right = buildTree(inorder,idxRoot + 1, inRight, postorder,postLeft + leftSize, postRight - 1 ,record);
        return new TreeNode(rootVal, left, right);
    }
}

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

与106思路一样,只是root的值来自于preorder数组的第一个值


class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        Map<Integer, Integer> record = new HashMap<>();
        for(int i = 0; i < inorder.length; i++){
            record.put(inorder[i], i);
        }
        return buildTree(preorder, 0, 0, inorder.length - 1, record);
    }
    private TreeNode buildTree(int[] preorder,int m, int inLeft, int inRight, Map<Integer, Integer> record ){
        if(inLeft > inRight) {
            return null;
        }

        int midVal = preorder[m];
        int mid = record.get(midVal);

        TreeNode left = buildTree(preorder, m + 1, inLeft, mid - 1,record);
        TreeNode right = buildTree(preorder, m + 1 + mid -inLeft, mid + 1, inRight,record);
        return new TreeNode(midVal, left, right);


    }
}

知识拓展:RFPDupeFilter 与请求指纹算法详解 Scrapy 2.17 去重源码详解:RFPDupeFilter 就是一个 set 加一个文件。拆解指纹算法,实测暴露默认端口与相对路径不归一化两个坑,给出规整中间件和自定义指纹方案。 阅读详情

相关推荐

数字取证双雄:Passware Kit Forensic 与 ElcomSoft 在实战场景下的能力边界解析

本文深入解析了Passware Kit Forensic与ElcomSoft在数字取证实战中的能力边界,涵盖Windows、macOS、iOS和Android系统的密码恢复与数据提取技术。通过真实案例对比两款工具在硬件加速、分布式计算及云取证等场景下的表现差异,为取证专家提供关键决策参考。特别探讨了密码恢复软件在加密设备突破中的核心作用。

weixin_30342209的博客 376

小红书 算法一面 十一

例如 **Soft MoE** 采用这种方式,大幅提升负载均衡性,但会增加计算开销。- **熵正则化**:直接最大化门控概率分布的熵,熵越大表示分布越均匀,公式为 $\mathcal{L}_{ent} = -\frac{1}{N}\sum_{i=1}^N\sum_{k=1}^K p_{ik}\log p_{ik}$。- **核心原理**:源自 **GShard** 和 **Switch Transformer**,通过最小化专家选择概率分布的熵,迫使门控网络给每个专家分配相近的 token 数量。

XLYcmy的博客 440

北斗导航 | 从零开始学习基于奇偶矢量的接收机自主完好性监测(RAIM)算法及改进

接收机自主完好性监测(Receiver Autonomous Integrity Monitoring, RAIM)是GNSS接收机内部的一种算法,它仅利用冗余的伪距观测量来判断定位结果是否可靠、是否存在故障卫星,并能识别和排除故障卫星。奇偶矢量法是RAIM最经典的实现方式之一,它将不可直接观测的测量误差映射到一个“奇偶空间”中,使故障检测变得简单且服从精确的概率分布。w\mathbf{w}w虽然能反映故障,但它的协方差矩阵不是单位阵,各分量相关,不利于统计检验。奇偶矢量通过一个正交变换P。

尘世冰封的专栏 373

数据库连接算法详解:从基础概念到嵌套循环优化

2.重复键在归并连接中的处理:排序归并连接遇到相同键时,需要保存或回溯同一键对应的记录组,然后输出笛卡尔积。(2)外连接:即使一方没有数据,也保留该侧数据,用NULL填充。对S中的键计算哈希值;(3)连接基数:连接结果的行数可能远大于任意一张输入表。设外表有R个页面,内表S个页面,比较次数O(R+R*S)5.哈希连接的限制:最适用于等值连接,不直接适用于比较。(1)build阶段:对较小的关系R建立哈希表。(1)内连接:只保留两张表之中能够匹配的内容。若R有M行,S有N行,则比较次数为O(MN)

jiangxiaohanya的博客 242

【数据结构】排序算法:归并排序与基数排序

本文介绍了归并排序和基数排序两种非比较型排序算法。归并排序采用分治策略,通过递归分割与合并实现排序,时间复杂度稳定为O(nlogn),空间复杂度O(n),具有稳定性。基数排序则基于数字位数进行分配收集,时间复杂度O(d(n+r)),适用于固定位数的整数或字符串排序。文章通过示例详细说明了两者的执行过程,并对比了八大排序算法的关键特性,包括时间复杂度、空间复杂度和稳定性。最后通过典型例题展示了两种排序的应用场景和解题思路,强调归并排序的分治思想和基数排序的LSD实现是考试重点。(149字)

bianyuan172的博客 281

LeetCode 1. 两数之和 | 从暴力枚举到哈希表最优解 + 空间换时间思想全复盘

文章摘要 题目要求在数组中找到两数之和等于目标值的下标。核心思路是优化查找效率: 暴力法:双重循环枚举所有数对,时间复杂度O(n²),效率低但易实现。 哈希表优化:利用哈希表O(1)查找特性,遍历时存储已访问元素,每次计算差值并查询,时间复杂度降至O(n)。关键细节是先查后存,避免自匹配。 代码实现:哈希表法通过一次遍历完成,空间换时间,边界处理需注意空数组和不足两元素的情况。 常见错误:内层循环起始点、哈希表键值设计、立即返回结果等易错点需警惕。 面试要点:优先选择哈希表解法,解释与暴力法的差异,强调时间

yc2284238579的博客 261

算法日常・每日刷题--<BFS>4

题目摘要: 给定一个由'X'和'O'组成的矩阵,要求捕获所有被'X'完全包围的'O'区域(即不与边界连通的区域),并将其替换为'X'。解法核心是逆向处理: 标记边界连通区域:遍历矩阵四边,对边界上的'O'进行BFS/DFS,标记所有与之连通的'O'为临时符号(如'.'),表示这些区域未被包围。 批量修改:遍历整个矩阵,将未被标记的'O'(被包围的)改为'X',同时恢复标记的'.'为'O'。 示例: 输入: [['X','X','X','X'], ['X','O','O','X'], ['X','X','O'

2503_92261635的博客 259

10.LeetCode算法习题讲解--滑动窗口--最大连续为一的个数

利用滑动窗口解决最大连续1的个数

Jammy_1的博客 223

算法日常・每日刷题--<BFS&&最短路径>4

675. 为高尔夫比赛砍树 - 力扣(LeetCode)675. 为高尔夫比赛砍树 - 你被请来给一个要举办高尔夫比赛的树林砍树。树林由一个 m x n 的矩阵表示, 在这个矩阵中: * 0 表示障碍,无法触碰 * 1 表示地面,可以行走 * 比 1 大的数 表示有树的单元格,可以行走,数值表示树的高度每一步,你都可以向上、下、左、右四个方向之一移动一个单位,如果你站的地方有一棵树,那么你可以决定是否要砍倒它。你需要按照树的高度从低向高砍掉所有的树,每砍过一颗树,该单元格的值变为 1(即变为地面)。

2503_92261635的博客 163

S 曲线加减速算法完整详解(C# 原生实现,无第三方库)

S 曲线加减速是工业运动控制核心轨迹规划算法,相比梯形曲线,依靠约束加加速度 Jerk 实现加速度连续变化,有效消除机械冲击与振动。本文完整讲解七段式 S 曲线原理、阶段推演、时间预规划逻辑,剖析短行程自动裁剪等工程难点。提供无第三方依赖原生 C# 完整实现,内置运动状态机,支持正反方向运动,基于解析多项式实时求解位置、速度、加速度,无积分累积误差。代码可直接用于伺服上位机、模组轨迹发生器,亦可精简移植嵌入式平台。同时对比算法优劣与适用场景,适合工控开发、伺服调试、嵌入式运动算法学习者参考。

工业上位机开发工程师,专注C#底层算法与工控仪器开发。从零手写信号滤波、曲线拟合、机器视觉、排序与密码学哈希,纯原生实现零第三方库,附数学推导与可编译源码,可移植STM32/PLC。 986

Tokenization(分词算法):一切大语言模型的地基

本文深入解析了Tokenization(分词算法)这一大语言模型的基础技术。Tokenization将原始文本切分为模型可处理的子词单元并映射为数字ID,是模型理解文本的第一步。

2301_80194949的博客 203

LeetCode 28. 找出字符串中第一个匹配项的下标(暴力匹配 + KMP 算法详解)

本文介绍了LeetCode 28题"找出字符串中第一个匹配项的下标"的两种解法:暴力匹配和KMP算法。暴力匹配通过逐个字符比较实现,时间复杂度O(m×n);KMP算法利用next数组跳过不必要匹配,时间复杂度O(m+n)。文章详细解释了KMP的核心思想,包括next数组的定义和构建过程,并提供了Python和Java的代码实现。两种方法各具特点:暴力匹配简单直观,KMP更高效但实现复杂,适合处理长字符串匹配问题。

2603_95532426的博客 231

一文读懂:字典序的第K小数字

可以按照层次遍历子树,firsti 指向第 i 层的最左侧的孩子节点, lasti 指向第 i 层的最右侧的孩子节点,根据推理可以知道: firsti = 10 × firsti − 1 ,lasti = 10 × lasti − 1 + 9 ,第 i 层共有 lasti − firsti + 1 个节点,由于所有的节点都需要满足小于等于 n ,所以第 i 层的最右侧节点应该为 min(n,lasti) ,不断迭代直到 firsti > n 则终止向下搜索。

2501_92927469的博客 213

算法效率的度量(上):时间复杂度中的对数思维

本文系统讲解算法时间复杂度的分析方法,重点解析对数和对数线性复杂度。主要内容包括:1)大O表示法的核心规则(保留最高阶项、忽略系数);2)对数复杂度O(logN)的三种典型场景(循环折半、二分查找、递归折半);3)对数线性复杂度O(NlogN)的结构特征(线性遍历嵌套折半操作);4)提供快速判断口诀和5道典型练习题(含递归分析)。通过代码示例和数学推导,揭示复杂度分析的本质是观察问题规模的缩减速度。

Guangyu536的博客 202

关于字符串【力扣151.反转字符串中的单词的思考】

【摘要】本文介绍了字符串反转问题的解决方案。通过三个关键步骤实现:首先去除多余空格,然后整体反转字符串,最后逐个反转单词。方法强调函数封装思想,将不同功能模块化处理。注意事项指出需特别关注函数封装在代码复用和维护中的重要性,这种分步处理方法能有效提高代码可读性和执行效率。

wasb666的博客 494

LeetCode 53 最大子数组和:一次遍历掌握 Kadane 算法

本文围绕 LeetCode 53“最大子数组和”展开,详细介绍 Kadane 算法的核心思想。通过定义以当前位置结尾的最大子数组和,判断是延续原有子数组还是从当前元素重新开始,并在遍历过程中维护全局最大值。文章结合示例演算、Java 代码和状态转移公式,分析全负数数组等边界情况,总结常见错误。该算法时间复杂度为 O(n),空间复杂度为 O(1)。

weixin_51228134的博客 477

leetcode 104二叉树的最大深度

为根的树深度是 1。

qq_63176310的博客 239

算法札记:利用floyd判环算法优化SPFA判负环算法

本文提出了一种优化SPFA算法检测负环的方法,使用Floyd判环算法替代传统的DFS判环。作者在SPFA中增加了计时器和Floyd判环(龟兔赛跑算法),当步数超过2n时启动判环检查。代码实现中,cycle()函数实现了Floyd判环逻辑,通过比较慢指针和快指针来检测环的存在。经测试,该优化在Acwing平台上比朴素SPFA快50倍,比基于栈的优化版本快1.2-1.4倍。这种方法显著提高了负环检测效率,尤其适用于大规模图论问题。

Keven_11的博客 292

分治题目:所有可能的真二叉树

二叉树中只有一个结点时,唯一的结点是根结点,没有子结点,因此是真二叉树,此时真二叉树中的结点数是奇数。个结点的真二叉树满足左子树和右子树的结点数都是奇数且左子树和右子树的结点数之和是。个结点时,将其中一个叶结点增加两个子结点之后仍为真二叉树,新的真二叉树中有。是奇数时,遍历左子树和右子树的结点数,然后递归地构造左子树和右子树。根据真二叉树的定义,真二叉树中的每个结点的子结点数是。真二叉树中的结点数是奇数,可以使用数学归纳法证明。答案的每个元素都是一个真二叉树的根结点。时只有一个结点的二叉树是真二叉树

stormsunshine的博客 162

DBC中如何实现报文传输类型属性的配置

AUTOSAR中CAN报文的传输类型主要有三种,周型,事件型和混合型。周型:按固定时间间隔自动发送,无需额外的触发条件。事件型:当信号值变化或满足内部条件时立即发送。混合型:默认按周发送,但事件触发时可提前发送。

sunchengl的博客 267

湖北省人口普查年鉴2020(EXCEL白金典藏版)

高价来的,回点儿血湖北省人口普查年鉴2020(EXCEL白金典藏版)│ ├─第1部分 全部数据资料│ ├─第1卷 概要│ │ │ ├─第2卷 民族 湖北省人口普查年鉴2020(EXCEL白金典藏版)list.txt (13.62 KB)

上一篇: 代码随想录算法训练营55期第十五天 | 二叉树part03
下一篇: 代码随想录算法训练营55期第十七天 | 二叉树part05
scorecpl
博客等级 码龄4年 73粉丝 30原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值