LeetCode--二叉树2--运用递归解决树的问题

在前面的章节中,我们已经介绍了如何利用递归求解树的遍历。

递归是解决树的相关问题最有效和最常用的方法之一。

我们知道,树可以以递归的方式定义为一个节点(根节点),它包括一个值和一个指向其他节点指针的列表。 递归是树的特性之一。

因此,许多树问题可以通过递归的方式来解决。

对于每个递归层级,我们只能关注单个节点内的问题,并通过递归调用函数来解决其子节点问题。

通常,我们可以通过 “自顶向下” 或 “自底向上” 的递归来解决树问题。

自顶向下的解决方案

“自顶向下” 意味着在每个递归层级,我们将首先访问节点来计算一些值,并在递归调用函数时将这些值传递到子节点。

所以 “自顶向下的解决方案可以被认为是一种前序遍历。

具体来说,递归函数 top_down(root, params) 的原理是这样的:

1. return specific value for null node
2. update the answer if needed // anwer <-- params
3. left_ans = top_down(root.left, left_params) // left_params <-- root.val, params
4. right_ans = top_down(root.right, right_params) // right_params <-- root.val, params
5. return the answer if needed // answer <-- left_ans, right_ans

例如,思考这样一个问题:给定一个二叉树,请寻找它的最大深度.

我们知道根节点的深度是1。

对于每个节点,如果我们知道某节点的深度,那我们将知道它子节点的深度。

因此,在调用递归函数的时候,将节点的深度传递为一个参数,那么所有的节点都知道它们自身的深度。

而对于叶节点,我们可以通过更新深度从而获取最终答案。

这里是递归函数 maximum_depth(root, depth) 的伪代码:

1. return if root is null
2. if root is a leaf node:
3. answer = max(answer, depth); // update the answer if needed
4. maximum_depth(root.left, depth + 1) // call the function recursively for left child
5. maximum_depth(root.right, depth + 1) // call the function recursively for right child
C++ 代码
int answer;		       // don't forget to initialize answer before call maximum_depth
void maximum_depth(TreeNode* root, int depth) {
if (!root) {
return;
}
if (!root->left && !root->right) {
answer = max(answer, depth);
}
maximum_depth(root->left, depth + 1);
maximum_depth(root->right, depth + 1);
}

自底向上的解决方案

“自底向上” 是另一种递归方法。

在每个递归层次上,我们首先对所有子节点递归地调用函数,然后根据返回值和根节点本身的值得到答案。

这个过程可以看作是后序遍历的一种。

通常, “自底向上” 的递归函数 bottom_up(root) 为如下所示:

1. return specific value for null node
2. left_ans = bottom_up(root.left) // call function recursively for left child
3. right_ans = bottom_up(root.right) // call function recursively for right child
4. return answers

让我们继续讨论前面关于树的最大深度的问题,但是使用不同的思维方式:

对于树的单个节点,以节点自身为根的子树的最大深度x是多少?

如果我们知道一个根节点,以其左子节点为根的最大深度为l和以其右子节点为根的最大深度为r,我们是否可以回答前面的问题?

当然可以,我们可以选择它们之间的最大值,再加上1来获得根节点所在的子树的最大深度。

那就是 x = max(l,r)+ 1。

这意味着对于每一个节点来说,我们都可以在解决它子节点的问题之后得到答案。

因此,我们可以使用“自底向上“的方法。

下面是递归函数 maximum_depth(root) 的伪代码:

return 0 if root is null                 // return 0 for null node
2. left_depth = maximum_depth(root.left)
3. right_depth = maximum_depth(root.right)
4. return max(left_depth, right_depth) + 1 // return depth of the subtree rooted at root
C++代码
int maximum_depth(TreeNode* root) {
if (!root) {
return 0; // return 0 for null node
}
int left_depth = maximum_depth(root->left);
int right_depth = maximum_depth(root->right);
return max(left_depth, right_depth) + 1; // return depth of the subtree rooted at root
}

二叉树的最大深度

 struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
}; class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == NULL)
return 0;
int left_depth = maxDepth(root->left);
int right_depth = maxDepth(root->right);
return max(left_depth,right_depth)+1;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int ans = 0 ;
int maxDepth(TreeNode* root) {
int dep = 1;
helper(root , dep);
return ans;
}
void helper(TreeNode* root ,int depth)
{
if(root == NULL)
return ;
if (root->right == NULL && root->left == NULL)
ans = max(ans , depth);
if(root->right != NULL)
helper(root->right,depth+1);
if (root-> left != NULL)
helper(root->left, depth+1);
}
};

对称二叉树

最初想法是,通过中序遍历,看中序遍历向量的是否首尾相等。

但是代码没有通过所有测试

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isSymmetric(TreeNode* root) {
vector<int> ans;
inorder(root,ans);
int back = ans.size();
for(int i = 0; i <= back/2 ; i++)
{
cout << ans[i] << endl;
if(ans[i] != ans[back-i-1])
return false;
}
return true;
} void inorder( TreeNode* root, vector<int> &order )
{
if(root == NULL)
{
return;
} if (root->left != NULL){
inorder(root->left,order);
} order.push_back(root->val); if(root->right != NULL){
inorder(root->right,order);
} }
};

转换想法:

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (root == NULL)
return true;
return helper(root->left , root->right); } bool helper (TreeNode* A,TreeNode* B)
{
if ( A == NULL && B == NULL)
return true;
if (A == NULL || B == NULL)
return false;
if (A->val != B->val)
return false;
return (helper(A->right,B->left)&&helper(A->left,B->right));
}
};

路径总和

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/ class Solution {
public:
bool hasPathSum(TreeNode* root, int sum) {
return helper(root,sum);
}
bool helper(TreeNode* cur, int sum)
{
if (cur == NULL)
return false;
if( cur->val == sum && cur->left == NULL && cur->right == NULL)
return true;
return (helper(cur->left , sum - cur->val) || helper(cur->right,sum - cur->val) );
}
};

逻辑:求二叉树的所有路径中,是否有与目标值相等的值

  1. 从上而下,当走到叶子节点的时候,检测是否为目标值

LeetCode--二叉树2--运用递归解决树的问题的更多相关文章

  1. LeetCode刷题笔记-递归-反转二叉树

    题目描述: 翻转一棵二叉树. 解题思路: 1.对于二叉树,立马递归 2.先处理 根节点,不需改动 3.处根的左子树和右子树需要交换位置 4.递归处理左子树和右子树.步骤见1-3步 Java代码实现: ...

  2. leetcode二叉树题目总结

    leetcode二叉树题目总结 题目链接:https://leetcode-cn.com/leetbook/detail/data-structure-binary-tree/ 前序遍历(NLR) p ...

  3. LeetCode Same Tree (判断相同树)

    题意:如题 思路:递归解决,同判断对称树的原理差不多.先保证当前两个结点是相等的,再递归保证两左结点是相等的,再递归保证右结点是相等的. /** * Definition for a binary t ...

  4. 二叉树3种递归和非递归遍历(Java)

    import java.util.Stack; //二叉树3种递归和非递归遍历(Java) public class Traverse { /******************一二进制树的定义*** ...

  5. 菜鸟笔记:node.js+mysql中将JSON数据构建为树(递归制作树状菜单数据接口)

    初学Web端开发,今天是第一次将所学做随笔记录,肯定存在多处欠妥,望大家海涵:若有不足,望大家批评指正. 进实验室后分配到的第一个项目,需要制作一个不确定层级树形菜单的数据接口,对于从来没实战编过程的 ...

  6. K:二叉树的非递归遍历

    相关介绍:  二叉树的三种遍历方式(先序遍历,中序遍历,后序遍历)的非递归实现,虽然递归方式的实现较为简单且易于理解,但是由于递归方式的实现受其递归调用栈的深度的限制,当递归调用的深度超过限制的时候, ...

  7. ZT 二叉树的非递归遍历

    ZT 二叉树的非递归遍历 二叉树的非递归遍历 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就 是递归定 ...

  8. LeetCode二叉树实现

    LeetCode二叉树实现 # 定义二叉树 class TreeNode: def __init__(self, x): self.val = x self.left = None self.righ ...

  9. 二叉树遍历,递归,栈,Morris

    一篇质量非常高的关于二叉树遍历的帖子,转帖自http://noalgo.info/832.html 二叉树遍历(递归.非递归.Morris遍历) 2015年01月06日 |  分类:数据结构 |  标 ...

随机推荐

  1. 用命令修改Oracle数据库密码

    1.改密码    (1).打开doc命令框键入:sqlplus /nolog     (2).输入:connect / as sysdba     (3).修改密码:alter user userNa ...

  2. 一、linux-mysql 运维DBA介绍

    一.DBA数据库管理人员需要在整个架构中解决数据库的压力,前端业务通过扩展,加机器就可以很好的解决,但是存储.数据库就不是很好的可以进行扩展,数据也是分配不均的,所以,1)通过在数据库前面添加Memc ...

  3. java静态方法和静态字段

    public class Dog{ public static void main(String[]args){ A a= new A(); a.add(); //java实例对象可以访问类的静态方法 ...

  4. day14-单继承

    #面向对象的三大特征:继承.多态.封装. #一.单继承: # 1. class Animal: #没有父类,默认继承了顶级父类object类. def __init__(self,name,aggr, ...

  5. cmd释放重新获取IP

    1.打开电脑的命令提示符运行设置窗口之后,我们收入  ipconfig/release  ,然后点击回车键  ,释放之前获取的IP地址 2.释放之前的IP地址之后,我们在输入  ipconfig/re ...

  6. linux重定向与管道符(一)

    linux重定向和管道符 为什么要使用重定向 1.当屏幕输出的信息很重要,而且我们需要将他存下来的时候: 2.后台执行中的程序,不希望他干扰屏幕正常的输出结果时: 3.系统的例行命令,例如定时任务的执 ...

  7. jquery时间控件

    jQuery 时间控件推荐 博客分类: jQuery 时间控件   My97DatePicker  My97DatePicker是一个更全面,更人性化,并且速度一流的日期选择控件.具有强大的日期范围限 ...

  8. java中的赋值

    java中的赋值使用符号“=”. 按照java编程思想的解释:它的意思是“取等号右边的值,把它复制给左边”. 当然左边必须是一个明确的,已命名的变量. 基本类型: int a=2; int b=3; ...

  9. 微弱信号二次谐波检测的FPGA的实现-总结

    首先还是把握大的系统框架: 我要实现的部分不包括DA以及AD的转换,主要是将SSP接收到的数据送入到FIFO中,然后经过FIR带通滤波器的处理后对该信号计算幅值并做PSD,然后处理的信号经过积分够一方 ...

  10. Office Lens:口袋中的扫描仪

    Lens:口袋中的扫描仪" title="Office Lens:口袋中的扫描仪"> 编者按:开会时,你是否觉得白板上天马行空的讨论记录誊抄起来费时费事又难以共享- ...