前言
二叉树与递归
文章目录
- 前言
- 一、第一种方法
- 1、如何思考二叉树相关的问题?
- 1)最大深度的定义
- 2)由具体到一般
- 3)公式
- 4)总结
- 2、为什么需要使用递归?
- 1)循环和递归
- 2)递和归的过程
- 3、为什么这样写是对的?
- 4、代码
- 二、第二种方法
- 1、思路
- 2、代码
一、第一种方法
1、如何思考二叉树相关的问题?
LeetCode 104. 二叉树的最大深度 原题链接
1)最大深度的定义
根节点到最远叶子节点最长路径上的节点数。
2)由具体到一般
不要一上来就陷入二叉树的细节,将题目中给的具体的二叉树结构转换成一般的二叉树的结构进行分析,三角形表示子树。
3)公式
整棵树的最大深度 = max(左子树的最大深度,右子树的最大深度) + 1。
4)总结
原问题:计算整棵树的最大深度。
子问题:计算左/右子树的最大深度。
计算左子树最大深度和右子树的最大深度与计算整棵树的最大深度是相似的。
2、为什么需要使用递归?
1)循环和递归
类比循环,循环就是在重复执行同样一份代码,计算子问题和原问题也应用一份代码来计算。
注意与循环是有区别的,例如,写一个循环去计算数组的元素和。做法为遍历数组中的每个数将值加到一个循环外的变量,每次循环加的都是同一个循环外的变量。
然而这个问题是有嵌套关系的,需要将计算结果返回给它的上一级问题,而它的上一级问题又会将计算结果返回给上上一级问题,依次类推,所以使用递归实现更合适。
2)递和归的过程
从原问题出发,不断将问题分解成规模更小的子问题,这个过程是递。
不断递下去,总会有个尽头,这个尽头就是递归的边界条件。此问题中边界条件就是空节点,直接返回 0 作为答案,返回的过程就是归。
这样,边界条件和非边界条件都弄清楚了。
3、为什么这样写是对的?
最简单和常见的数学归纳法是证明当n
等于任意一个自然数时某命题成立。证明分下面两步:
- 证明“当n=1时命题成立。”(选择数字
1
因其作为自然数集合中中最小值) - 证明“若假设在n=m时命题成立,可推导出在
n=m+1
时命题成立。(m代表任意自然数)”
这种方法的原理在于:首先证明在某个起点值时命题成立,然后证明从一个值到下一个值的过程有效。当这两点都已经证明,那么任意值都可以通过反复使用这个方法推导出来。把这个方法想成多米诺骨牌效应也许更容易理解一些。2lB]例如:你有一列很长的直立着的多米诺骨牌,如果你可以:
- 证明“第一张骨牌会倒。”
- 证明“只要任意一张骨牌倒了,其下一张骨牌也会因为前面的骨牌倒而跟著倒。
则可下结论:所有的骨牌都会倒下。
4、代码
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == NULL) return 0;
int l_depth = maxDepth(root->left);
int r_depth = maxDepth(root->right);
return max(l_depth, r_depth) + 1;
}
};
时间复杂度为 O ( n ) O(n) O(n),尾音每个节点都会遍历了一次。
二、第二种方法
1、思路
在递归的时候除了将节点传下去,还可以将路径上的节点个数传下去,根节点个数为1
。
在递归的同时可以维护一个全局变量,每次+1
之后都更新这个全局变量的最大值。
遍历完整棵树,这个全局变量就是答案。
2、代码
class Solution {
public:
int ans = 0;
void dfs(TreeNode* root, int cnt) {
if (root == NULL) return;
cnt += 1;
dfs(root->left, cnt);
dfs(root->right, cnt);
ans = max(ans, cnt);
}
int maxDepth(TreeNode* root) {
dfs(root, 0);
return ans;
}
};