代码随想录算法训练营第十七天 | 回溯、深度与高度

别再手动敲代码了!用STM32CubeMX+FreeRTOS图形化配置,5分钟搞定多任务通信框架 本文详细介绍了如何利用STM32CubeMX和FreeRTOS快速搭建多任务通信框架,大幅提升嵌入式开发效率。通过图形化配置工具,开发者可在5分钟内完成任务调度、时钟配置和内核对象生成,特别适合物联网设备开发。文章还提供了代码优化和调试技巧,帮助开发者轻松应对复杂应用场景。 阅读详情

目录

力扣题目

力扣题目记录

110.平衡二叉树

257. 二叉树的所有路径

递归

404.左叶子之和

总结


力扣题目

用时:1.5h

1、110.平衡二叉树

2、257. 二叉树的所有路径

3、404.左叶子之和


力扣题目记录

110.平衡二叉树

咋眼一看这道题目和104.二叉树的最大深度 (opens new window)很像,其实有很大区别。

这里强调一波概念:

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。

但leetcode中强调的深度和高度很明显是按照节点来计算的,如图:

110.平衡二叉树2

因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)

为什么104.二叉树的最大深度 (opens new window)中求的是二叉树的最大深度,也用的是后序遍历。

那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这棵树的最大深度,所以才可以使用后序遍历。

在104.二叉树的最大深度 (opens new window)中,如果真正求取二叉树的最大深度,代码应该写成如下:(前序遍历)

class Solution {
public:
    int result;
    void getDepth(TreeNode* node, int depth) {
        result = depth > result ? depth : result; // 中

        if (node->left == NULL && node->right == NULL) return ;

        if (node->left) { // 左
            depth++;    // 深度+1
            getDepth(node->left, depth);
            depth--;    // 回溯,深度-1
        }
        if (node->right) { // 右
            depth++;    // 深度+1
            getDepth(node->right, depth);
            depth--;    // 回溯,深度-1
        }
        return ;
    }
    int maxDepth(TreeNode* root) {
        result = 0;
        if (root == NULL) return result;
        getDepth(root, 1);
        return result;
    }
};

可以看出使用了前序(中左右)的遍历顺序,这才是真正求深度的逻辑!

注意以上代码是为了把细节体现出来,简化一下代码如下:

class Solution {
public:
    int result;
    void getDepth(TreeNode* node, int depth) {
        result = depth > result ? depth : result; // 中
        if (node->left == NULL && node->right == NULL) return ;
        if (node->left) { // 左
            getDepth(node->left, depth + 1);
        }
        if (node->right) { // 右
            getDepth(node->right, depth + 1);
        }
        return ;
    }
    int maxDepth(TreeNode* root) {
        result = 0;
        if (root == 0) return result;
        getDepth(root, 1);
        return result;
    }
};

递归三步曲分析:

  • 明确递归函数的参数和返回值

参数:当前传入节点。 返回值:以当前传入节点为根节点的树的高度。

那么如何标记左右子树是否差值大于1呢?

如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。

所以如果已经不是二叉平衡树了,可以返回-1 来标记已经不符合平衡树的规则了。

代码如下:

// -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
int getHeight(TreeNode* node)
  • 明确终止条件

递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0

代码如下:

if (node == NULL) {
    return 0;
}
  • 明确单层递归的逻辑

如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值。

分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。

代码如下:

int leftHeight = getHeight(node->left); // 左
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right); // 右
if (rightHeight == -1) return -1;

int result;
if (abs(leftHeight - rightHeight) > 1) {  // 中
    result = -1;
} else {
    result = 1 + max(leftHeight, rightHeight); // 以当前节点为根节点的树的最大高度
}

return result;

代码精简之后如下:

int leftHeight = getHeight(node->left);
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right);
if (rightHeight == -1) return -1;
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);

此时递归的函数就已经写出来了,这个递归的函数传入节点指针,返回以该节点为根节点的二叉树的高度,如果不是二叉平衡树,则返回-1。

最后本题整体递归代码如下:

class Solution {
public:
    // 返回以该节点为根节点的二叉树的高度,如果不是平衡二叉树了则返回-1
    int getHeight(TreeNode* node) {
        if (node == NULL) {
            return 0;
        }
        int leftHeight = getHeight(node->left);
        if (leftHeight == -1) return -1;
        int rightHeight = getHeight(node->right);
        if (rightHeight == -1) return -1;
        return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
    }
    bool isBalanced(TreeNode* root) {
        return getHeight(root) == -1 ? false : true;
    }
};

257. 二叉树的所有路径

这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。

在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。

前序遍历以及回溯的过程如图:

257.二叉树的所有路径

我们先使用递归的方式,来做前序遍历。要知道递归和回溯就是一家的,本题也需要回溯。

递归

  • 递归函数参数以及返回值

要传入根节点,记录每一条路径的path,和存放结果集的result,这里递归不需要返回值,代码如下:

void traversal(TreeNode* cur, vector<int>& path, vector<string>& result)
  • 确定递归终止条件

在写递归的时候都习惯了这么写:

if (cur == NULL) {
    终止处理逻辑
}

但是本题的终止条件这样写会很麻烦,因为本题要找到叶子节点,就开始结束的处理逻辑了(把路径放进result里)。

那么什么时候算是找到了叶子节点? 是当 cur不为空,其左右孩子都为空的时候,就找到叶子节点。

所以本题的终止条件是:

if (cur->left == NULL && cur->right == NULL) {
    终止处理逻辑
}

为什么没有判断cur是否为空呢,因为下面的逻辑可以控空节点不入循环

再来看一下终止处理的逻辑。

这里使用vector 结构path来记录路径,所以要把vector 结构的path转为string格式,再把这个string 放进 result里。

那么为什么使用了vector 结构来记录路径呢? 因为在下面处理单层递归逻辑的时候,要做回溯,使用vector方便来做回溯。

可能有的同学问了,我看有些人的代码也没有回溯啊。

其实是有回溯的,只不过隐藏在函数调用时的参数赋值里,下文我还会提到。

这里我们先使用vector结构的path容器来记录路径,那么终止处理逻辑如下:

if (cur->left == NULL && cur->right == NULL) { // 遇到叶子节点
    string sPath;
    for (int i = 0; i < path.size() - 1; i++) { // 将path里记录的路径转为string格式
        sPath += to_string(path[i]);
        sPath += "->";
    }
    sPath += to_string(path[path.size() - 1]); // 记录最后一个节点(叶子节点)
    result.push_back(sPath); // 收集一个路径
    return;
}
  • 确定单层递归逻辑

因为是前序遍历,需要先处理中间节点,中间节点就是我们要记录路径上的节点,先放进path中。

path.push_back(cur->val);

然后是递归和回溯的过程,上面说过没有判断cur是否为空,那么在这里递归的时候,如果为空就不进行下一层递归了。

所以递归前要加上判断语句,下面要递归的节点是否为空,如下

if (cur->left) {
    traversal(cur->left, path, result);
}
if (cur->right) {
    traversal(cur->right, path, result);
}

此时还没完,递归完,要做回溯啊,因为path 不能一直加入节点,它还要删节点,然后才能加入新的节点。

那么回溯要怎么回溯呢,一些同学会这么写,如下:

if (cur->left) {
    traversal(cur->left, path, result);
}
if (cur->right) {
    traversal(cur->right, path, result);
}
path.pop_back();

这个回溯就有很大的问题,我们知道,回溯和递归是一一对应的,有一个递归,就要有一个回溯,这么写的话相当于把递归和回溯拆开了, 一个在花括号里,一个在花括号外。

所以回溯要和递归永远在一起,世界上最遥远的距离是你在花括号里,而我在花括号外!

那么代码应该这么写:

if (cur->left) {
    traversal(cur->left, path, result);
    path.pop_back(); // 回溯
}
if (cur->right) {
    traversal(cur->right, path, result);
    path.pop_back(); // 回溯
}

那么本题整体代码如下:

// 版本一
class Solution {
private:

    void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {
        path.push_back(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中 
        // 这才到了叶子节点
        if (cur->left == NULL && cur->right == NULL) {
            string sPath;
            for (int i = 0; i < path.size() - 1; i++) {
                sPath += to_string(path[i]);
                sPath += "->";
            }
            sPath += to_string(path[path.size() - 1]);
            result.push_back(sPath);
            return;
        }
        if (cur->left) { // 左 
            traversal(cur->left, path, result);
            path.pop_back(); // 回溯
        }
        if (cur->right) { // 右
            traversal(cur->right, path, result);
            path.pop_back(); // 回溯
        }
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        vector<int> path;
        if (root == NULL) return result;
        traversal(root, path, result);
        return result;
    }
};

如上的C++代码充分体现了回溯。

那么如上代码可以精简成如下代码:

class Solution {
private:

    void traversal(TreeNode* cur, string path, vector<string>& result) {
        path += to_string(cur->val); // 中
        if (cur->left == NULL && cur->right == NULL) {
            result.push_back(path);
            return;
        }
        if (cur->left) traversal(cur->left, path + "->", result); // 左
        if (cur->right) traversal(cur->right, path + "->", result); // 右
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        string path;
        if (root == NULL) return result;
        traversal(root, path, result);
        return result;

    }
};

如上代码精简了不少,也隐藏了不少东西。

注意在函数定义的时候void traversal(TreeNode* cur, string path, vector<string>& result) ,定义的是string path,每次都是复制赋值,不用使用引用,否则就无法做到回溯的效果。(这里涉及到C++语法知识)

那么在如上代码中,貌似没有看到回溯的逻辑,其实不然,回溯就隐藏在traversal(cur->left, path + "->", result);中的 path + "->"。 每次函数调用完,path依然是没有加上"->" 的,这就是回溯了。

为了把这份精简代码的回溯过程展现出来,大家可以试一试把:

if (cur->left) traversal(cur->left, path + "->", result); // 左  回溯就隐藏在这里

改成如下代码:

path += "->";
traversal(cur->left, path, result); // 左

即:

if (cur->left) {
    path += "->";
    traversal(cur->left, path, result); // 左
}
if (cur->right) {
    path += "->";
    traversal(cur->right, path, result); // 右
}

此时就没有回溯了,这个代码就是通过不了的了。

如果想把回溯加上,就要 在上面代码的基础上,加上回溯,就可以AC了。

if (cur->left) {
    path += "->";
    traversal(cur->left, path, result); // 左
    path.pop_back(); // 回溯 '>'
    path.pop_back(); // 回溯 '-'
}
if (cur->right) {
    path += "->";
    traversal(cur->right, path, result); // 右
    path.pop_back(); // 回溯 '>' 
    path.pop_back(); //  回溯 '-' 
}

整体代码如下:

//版本二
class Solution {
private:
    void traversal(TreeNode* cur, string path, vector<string>& result) {
        path += to_string(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中
        if (cur->left == NULL && cur->right == NULL) {
            result.push_back(path);
            return;
        }
        if (cur->left) {
            path += "->";
            traversal(cur->left, path, result); // 左
            path.pop_back(); // 回溯 '>'
            path.pop_back(); // 回溯 '-'
        }
        if (cur->right) {
            path += "->";
            traversal(cur->right, path, result); // 右
            path.pop_back(); // 回溯'>'
            path.pop_back(); // 回溯 '-'
        }
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        string path;
        if (root == NULL) return result;
        traversal(root, path, result);
        return result;

    }
};

大家应该可以感受出来,如果把 path + "->"作为函数参数就是可以的,因为并没有改变path的数值,执行完递归函数之后,path依然是之前的数值(相当于回溯了)

综合以上,第二种递归的代码虽然精简但把很多重要的点隐藏在了代码细节里,第一种递归写法虽然代码多一些,但是把每一个逻辑处理都完整的展现出来了。


404.左叶子之和

递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和。

递归三部曲:

  • 确定递归函数的参数和返回值

判断一个树的左叶子节点之和,那么一定要传入树的根节点,递归函数的返回值为数值之和,所以为int

使用题目中给出的函数就可以了。

  • 确定终止条件

如果遍历到空节点,那么左叶子值一定是0

if (root == NULL) return 0;

注意,只有当前遍历的节点是父节点,才能判断其子节点是不是左叶子。 所以如果当前遍历的节点是叶子节点,那其左叶子也必定是0,那么终止条件为:

if (root == NULL) return 0;
if (root->left == NULL && root->right== NULL) return 0; //其实这个也可以不写,如果不写不影响结果,但就会让递归多进行了一层。
  •  确定单层递归的逻辑

当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。

代码如下:

int leftValue = sumOfLeftLeaves(root->left);    // 左
if (root->left && !root->left->left && !root->left->right) {
    leftValue = root->left->val;
}
int rightValue = sumOfLeftLeaves(root->right);  // 右

int sum = leftValue + rightValue;               // 中
return sum;

整体递归代码如下:

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if (root == NULL) return 0;
        if (root->left == NULL && root->right== NULL) return 0;

        int leftValue = sumOfLeftLeaves(root->left);    // 左
        if (root->left && !root->left->left && !root->left->right) { // 左子树就是一个左叶子的情况
            leftValue = root->left->val;
        }
        int rightValue = sumOfLeftLeaves(root->right);  // 右

        int sum = leftValue + rightValue;               // 中
        return sum;
    }
};

以上代码精简之后如下:

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if (root == NULL) return 0;
        int leftValue = 0;
        if (root->left != NULL && root->left->left == NULL && root->left->right == NULL) {
            leftValue = root->left->val;
        }
        return leftValue + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
    }
};

我自己又写了一个版本

class Solution {
public:
    int sum = 0;
    void func(TreeNode* node, string leftOrRight)
    {
        
        if (node->left == NULL && node->right == NULL)
        {
            if (leftOrRight == "left")
            {
                sum += node->val;
            }
            return;
        }
        if (node->left)
        {
            func(node->left, "left");
        }
        if (node->right)
        {
            func(node->right, "right");
        }
        return;
    }

    int sumOfLeftLeaves(TreeNode* root) {
        if (root == NULL) return 0;
        func(root, "right");
        return sum;
    }
};

总结

        1、学习了回溯

        2、对递归理解加深

        3、高度用后序,深度用前序

参考:代码随想录

Python 安装 PyTorch(GPU)详细教程 本章教程,介绍如何安装PyTorch GPU版本的具体教程。 阅读详情

相关推荐

HackRF实战:用Portapack扩展板玩转GPS信号模拟(附固件刷写教程)

本文详细介绍了如何使用HackRF与Portapack扩展板进行GPS信号模拟,包括固件刷写、信号生成与发射配置等实战操作。通过专业工具和优化技巧,读者可以掌握软件无线电的高级应用,解决手机定位难题,同时强调安全合规使用的重要性。

weixin_28717431的博客 362

代码随想录算法训练营第十七天 | LeetCode 110. 平衡二叉树、257. 二叉树的所有路径、404. 左叶子之和

【代码】代码随想录算法训练营第十七天 | LeetCode 110. 平衡二叉树、257. 二叉树的所有路径、404. 左叶子之和。

Hsusan的博客 307

并网逆变器学习笔记5---三电平DPWM

三电平DPWM

圆桌骑士的博客 1万+

代碼隨想錄算法訓練營|第十七天|110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和 。刷题心得(c++)

目录 讀題 110.平衡二叉树 自己看到题目的第一想法 看完代码随想录之后的想法 257.二叉树的所有路径 自己看到题目的第一想法 看完代码随想录之后的想法 404.左叶子之和 自己看到题目的第一想法 看完代码随想录之后的想法 110.平衡二叉树 - 實作 思路 錯誤思路 正確思路 Code 錯誤代碼 正確代碼 257.二叉树的所有路径 - 實作 思路 Code 思考 404.左叶子之和 - 實作 思路 Code 總結 自己实现过程中遇到哪些困难 今

RVLIN的博客 1307

Fastjson2升级指南:如何平滑迁移并避免兼容性问题

本文详细介绍了Fastjson2的升级指南,涵盖兼容性检查、性能调优及零停机迁移方案。通过实战案例展示如何避免常见问题,如日期格式严格校验和字段映射策略变化,并分享高性能配置技巧如JSONB二进制协议和内存池化。帮助开发者平滑迁移至Fastjson2,提升JSON处理效率。

weixin_29016865的博客 410

YOLOv10改进策略【注意力机制篇】| 2024 蒙特卡罗注意力(MCAttn)模块,提高小目标的关注度

本文记录的是基于蒙特卡罗注意力(MCAttn)模块的YOLOv10目标检测改进方法研究。利用提高的跨尺度特征提取能力,使模型能够更好地传递和融合提取的多尺度特征,提高对小目标的关注度。Exploiting Scale-Variant Attention for Segmenting Small Medical Objects使用一种基于随机采样的池化操作来生成尺度无关的注意力图。它从三个不同尺度(3×33×33×3、2×22×22×2和1×11×11×1,即池化张量)中随机选择一个1×11×11×1注意力图

Limiiiing的博客 2185

代码随想录算法训练营第十七天| 110.平衡二叉树, 257. 二叉树的所有路径, 404.左叶子之和

代码随想录题解:​​​​​​​。

qq_42973684的博客 805

【26美赛B题】2026美赛数学建模(MCM/ICM)思路解析及代码分享

2026美赛数学建模B题解析与备赛指南:本文针对B题"数据+预测+决策优化"的特点,提出通用建模路线图,包含数据预处理、特征工程、预测模型构建、策略优化和稳定性验证等关键环节。提供赛题拆解方法、Python/Matlab双实现方案、AI辅助建模技巧及论文写作模板。适用于2026美赛B题参赛者及其他数学建模竞赛选手,帮助掌握从数据到决策的闭环建模流程,特别强调逻辑严谨性和结果可视化呈现。订阅者可获取历年真题解析和持续更新的备赛资源。

一键难忘的博客 2109

代码随想录算法训练营第十七天 | 110. 平衡二叉树,257. 二叉树的所有路径,404. 左叶子之和

再一次涉及到,什么是高度,什么是深度,可以巩固一下。

Triple_3的博客 197

ccSwitch 安装使用指南,claude code的最佳搭档

ccSwitch 是一款真正为 AI 编程开发者打造的效率工具。它把原本繁琐的配置管理工作,简化成了直观的图形界面操作。无论你是需要在多个 API 提供商之间切换,还是想要统一管理多款 AI 编程工具,ccSwitch 都能帮你大幅提升效率。如果你是重度 AI 编程工具用户,强烈推荐尝试一下 ccSwitch,相信它会成为你开发工具箱中不可或缺的一员。项目地址。

篮球界最会写bug的人;程序猿中打球最菜的人。 1281

伺服系统控制原理深度解析

摘要:本文系统阐述了伺服系统的控制原理与应用。首先介绍了伺服系统的定义、组成及其在工业自动化中的重要性;然后详细分析了反馈控制机制、稳定性判据和性能指标;重点推导了传递函数和状态空间两种数学模型,并通过LaTeX公式展示了二阶系统建模过程;进而对比了PID控制、状态反馈及自适应控制等方法的优缺点;最后结合数控机床等案例,验证了理论方法的有效性,并展望了伺服系统智能化发展趋势。全文兼顾理论深度与实践指导性,为控制工程领域提供了系统的技术参考。

技术工作者 1263

代码随想录算法训练营第十七天

我的思路在每一次遇到根节点都计算左右节点的高度来进行比较,最后确定该节点是否为平衡二叉树,好像在执行过程中不止一次计算了同一部分节点的高度,所以应该将逻辑整合在同一函数中,将-1代表为当前二叉树不是平衡二叉树,就不会多重计算部分节点。我的代码通过了,但是在思路方面我觉得代码随想录中的代码给出的更具有规范,它将所有处理过程规整在同一个函数中处理,可以将所有过程变为一个递归过程,而我的代码多少有点冗余,可以将 它的代码进行参考。在第二段代码中,十分巧妙地利用参数特性来实现了回溯,可以多多参悟。

sssuez的博客 72

解决Jupyter Notebook中Plotly图表显示问题

摘要:在Jupyter Notebook中使用Plotly绘图时遇到图表无法显示的问题。通过分析发现Python 3.12版本与Jupyter存在兼容性问题。解决方案是将Python降级到3.11版本,重新创建虚拟环境后图表正常显示。这表明版本兼容性对数据可视化工具至关重要,环境配置检查是解决问题的关键步骤。该案例为遇到类似问题的开发者提供了参考方案。

m0_74337424的博客 124

代码随想录算法训练营第十七天|110.平衡二叉树,257. 二叉树的所有路径,404.左叶子之和

范例中的思路是用一个vector存储路径上的节点,当左右孩子节点都为空时,将存储在,vector里的节点修饰成一个字符串,并存入结果vector中,向左向右进行遍历时,递归之后跟一个回溯。分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。这是大家第一次接触到回溯的过程, 我在视频里重点讲解了 本题为什么要有回溯,已经回溯的过程。递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0。,返回所有从根节点到叶子节点的路径。

2302_77519551的博客 465

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

代码随想录算法训练营第十七天|110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和

判断二叉树是否为平衡二叉树。:判读二叉树遍历方式为左右根,求高度遍历方式也为左右根。:如果当前节点为空或者为叶子结点,则返回true;如果不为空或者为叶子结点,则判断左右子树高度差十分大于1,大于一则直接返回fasle,小于一要判断左右子树收否都为平衡二叉树,如果不是则返回fasle。

XiaoKeer666的博客 538

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

代码随想录算法训练营第十七天 | 110.平衡二叉树,257. 二叉树的所有路径,404.左叶子之和

判断一个树的左叶子节点之和,那么一定要传入树的根节点,递归函数的返回值为数值之和,所以为int,使用题目中给出的函数就可以了。注意,只有当前遍历的节点是父节点,才能判断其子节点是不是左叶子。当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。如果该节点的左节点不为空,该节点的左节点的左节点为空,该节点的左节点的右节点为空,则找到了一个左叶子。

qwerty0157的博客 489

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

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

这是需要使用回溯算法需要解决的题目,因为需要记录以根节点为起点的所有路径,所以需要使用前序遍历,并且设置path数组记录路径,result数组添加结果,这是一道真正的回溯算法题,第一次做感觉有点难,需要后续不断练习才行。本来是一道很简单的题,但是题目表述却非常绕,例子也给的少所以有点不明所以,画图搞懂以后就明白了,我们等一个结点有左孩子,且这个左孩子没有孩子结点的时候,这个孩子结点就是左叶子。给定一个二叉树,判断它是否是高度平衡的二叉树。,返回所有从根节点到叶子节点的路径。是指没有子节点的节点。

weixin_50925435的博客 207

代码随想录算法训练营第十七天 | 110. 平衡二叉树、257. 二叉树的所有路径、404.左叶子之和

肯定是要遍历,那就用递归法,==这里总结一下心得,用递归法深度遍历就要考虑哪种遍历顺序,根据就是要做什么处理,比如这道题,要判断子树的信息,那就是后序遍历。==定义递归函数的意义:返回以传入节点为根节点的树的高度。一个细节就是判断是否为高度平衡二叉树,用-1表示不是,如果子节点不是高度平衡二叉树,那当前的节点也肯定不是了,算是一个小优化。我的理解就是有递归就要有回溯,但是是有前提的,前提就是只有当递归以后改变了传入参数的信息,并且传入参数在本次递归中还需要利用的就需要回溯,也就是把修改的内容去除掉。

Tong_1024_的博客 832

代码随想录算法训练营第十七天|110、257、404

递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和。迭代前中后序都可以,统计左叶子节点之和。递归求高度的返回值,如果当前入根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了,返回-1作为标记。笔记:通过前序遍历,让父节点指向孩子节点,找到对应的路径。隐形回溯就是把左右节点的路径独立,互相不影响。其实本题有点文字游戏,搞清楚什么是左叶子,剩下的就是二叉树的基本操作。笔记:左叶子定义和判断(要通过节点的父节点来判断其左孩子是不是左叶子)。

Adaliudh的博客 529

代码随想录算法训练营第十七天 |LeetCode110.平衡二叉树、LeetCode257.二叉树的所有路径、LeetCode404 .左叶子之和

巩固一下二叉树中高度和深度的概念。

m0_64514622的博客 1800

代码随想录算法训练营第十七天【二叉树】|110,257,404

此处代码用后序遍历,只要有一个节点不是平衡就返回-1,之后所有上层节点都是-1。要用前序遍历(中左右):要让parent node指向child node。中要写到终止条件(判断叶子节点)前,不然叶子节点就放不进去了。左孩子不为null,但左孩子的左右孩子为null。求深度:前序遍历 ,从上往下,不需要返回结果。是否平衡:每个节点的左右子树高度差小于1。求高度:后序遍历,从下往上,层层往上返回。

steph766的博客 397

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

一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 递归三部曲: 257. 二叉树的所有路径 这道题很难,题目需要求从根节点到叶子的路径,我们需要使用的是前序遍历(中左右)。 由于我们需要求的是所有路径,因此我们需要使用回溯来回退一个路径再进入另一个路径。 还是递归三部曲: 111.二叉树的最小深度 这道题一定要避免误区,最小深度是从根节点到最近叶子节点深度。 所以我们的目标就很明确了,在递归的基础上进行分类讨论。 404.左叶子之和 确定单层递归的逻辑: 当遇到左叶

qq_17027283的博客 443

代码随想录算法训练营第十七天|110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和

二叉树

m0_52925186的博客 314

代码随想录算法训练营第十七天 | 110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和

代码随想录算法训练营第十七天 | 110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和

叫我豆包就好了的博客 183

代码随想录算法训练营第十七天|110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和

110. 平衡二叉树 - 力扣(LeetCode)给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。示例 1: 输入:root = [3,9,20,null,null,15,7] 输出:true 示例 2: 输入:root = [1,2,2,3,3,null,null,4,4] 输出:false 示例 3:输入:root = [] 输出:true 提示:树中的节点数在范围 [0, 5000] 内 -104 <=

HSL13594379250的博客 74

代码随想录算法训练营第十七天|110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和

这个题可以轻松的判断只不是叶子节点,难点在于怎么判断它是不是左节点呢。所以不判断到叶子结点,而是判断到叶子结点的父节点,然后再判断该节点的左节点的左右孩子是不是都为空。将当前节点的val加入list后,判断左右孩子的状态,然后再递归,找另外一条路径需要返回上一个节点,val的list列表需要remove。采用后序遍历的递归方式来解决问题,因为当前节点的深度需要下一层节点深度返回加一,所以递归选择左右中的遍历方式。,返回所有从根节点到叶子节点的路径。是指没有子节点的节点。,返回所有左叶子之和。

leeld的博客 375
上一篇: 代码随想录算法训练营第十六天 | 二叉树的深度、节点个数
下一篇: 代码随想录算法训练营第十八天 | 前中后序构造二叉树
Fight___
博客等级 码龄7年 275粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值