LeetCode--二叉树2--运用递归解决树的问题
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) );
}
};
逻辑:求二叉树的所有路径中,是否有与目标值相等的值
- 从上而下,当走到叶子节点的时候,检测是否为目标值
LeetCode--二叉树2--运用递归解决树的问题的更多相关文章
- LeetCode刷题笔记-递归-反转二叉树
题目描述: 翻转一棵二叉树. 解题思路: 1.对于二叉树,立马递归 2.先处理 根节点,不需改动 3.处根的左子树和右子树需要交换位置 4.递归处理左子树和右子树.步骤见1-3步 Java代码实现: ...
- leetcode二叉树题目总结
leetcode二叉树题目总结 题目链接:https://leetcode-cn.com/leetbook/detail/data-structure-binary-tree/ 前序遍历(NLR) p ...
- LeetCode Same Tree (判断相同树)
题意:如题 思路:递归解决,同判断对称树的原理差不多.先保证当前两个结点是相等的,再递归保证两左结点是相等的,再递归保证右结点是相等的. /** * Definition for a binary t ...
- 二叉树3种递归和非递归遍历(Java)
import java.util.Stack; //二叉树3种递归和非递归遍历(Java) public class Traverse { /******************一二进制树的定义*** ...
- 菜鸟笔记:node.js+mysql中将JSON数据构建为树(递归制作树状菜单数据接口)
初学Web端开发,今天是第一次将所学做随笔记录,肯定存在多处欠妥,望大家海涵:若有不足,望大家批评指正. 进实验室后分配到的第一个项目,需要制作一个不确定层级树形菜单的数据接口,对于从来没实战编过程的 ...
- K:二叉树的非递归遍历
相关介绍: 二叉树的三种遍历方式(先序遍历,中序遍历,后序遍历)的非递归实现,虽然递归方式的实现较为简单且易于理解,但是由于递归方式的实现受其递归调用栈的深度的限制,当递归调用的深度超过限制的时候, ...
- ZT 二叉树的非递归遍历
ZT 二叉树的非递归遍历 二叉树的非递归遍历 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就 是递归定 ...
- LeetCode二叉树实现
LeetCode二叉树实现 # 定义二叉树 class TreeNode: def __init__(self, x): self.val = x self.left = None self.righ ...
- 二叉树遍历,递归,栈,Morris
一篇质量非常高的关于二叉树遍历的帖子,转帖自http://noalgo.info/832.html 二叉树遍历(递归.非递归.Morris遍历) 2015年01月06日 | 分类:数据结构 | 标 ...
随机推荐
- [徐州网络赛]Longest subsequence
[徐州网络赛]Longest subsequence 可以分成两个部分,前面相同,然后下一个字符比对应位置上的大. 枚举这个位置 用序列自动机进行s字符串的下标转移 注意最后一个字符 #include ...
- [HDU多校]Ridiculous Netizens
[HDU多校]Ridiculous Netizens 点分治 分成两个部分:对某一点P,连通块经过P或不经过P. 经过P采用树形依赖背包 不经过P的部分递归计算 树型依赖背包 v点必须由其父亲u点转移 ...
- vue项目post、put、delete、get向java后端传数组
通常我们向后端发送数据有两种方式 get.post,后又restful风格出现,又有put.delete等传参方式.但是对于我们来说他们的传参本质还是只有get和post的两种,即 get.delet ...
- struts-dojo的使用
1.导入struts2-dojo-plugin-2.1.8.jar 2.在用使用dojo的页面引入 <span style="font-size:14px;">< ...
- Leetcode14._最长公共前缀
题目 编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow&q ...
- 玩转SpringBoot用好条件相关注解,开启自...
官方提供的常用条件注解 因为Spring的核心是基于bean的,所以这些条件注解主要是影响bean的注册. 因为注册的bean不同了,最后对外呈现的行为就不同了.不就是自动配置了. 一.最常用的应该是 ...
- Memcached的批量删除方案总结
Memcached的批量删除,向来是Memcached使用者很头疼的事情,因为Memcached采取的缓存方案是哈希表结构,所以没有办法实现delete from tablename where ke ...
- labview状态机
状态机主要由3部分组成,包括一个while循环,一个条件结构,以及while循环的移位寄存器,其中while循环用于保证程序的持续运行,条件结构用于处理不同状态的执行,移位寄存器用于实现从一个状态跳转 ...
- Windows Server 2012 R2 强制卸载域控制器
本次实验要演示的是强制卸载域控制器并且在其他域控制器上删除不需要的服务器对象,这种情况在现实的生产使用环境中经常使用,每个企业每年都会有增减域控制器的时候,而且在减少了域控制器之后,原本的域还会继续使 ...
- nodejs 模块变量 应用
exports.allcodeandname=(function(){ var fs = require('fs'); var data = fs.readFileSync(__dirname+'/a ...