【递归】8. leetcode 671 二叉树中第二小的节点
题目描述
题目链接:二叉树中第二小的节点
2 解答思路
注意这句话:该节点的值等于两个子节点中较小的一个
二叉树的根节点的值是整棵树中最小的值
本道题所要求的是二叉树中第二小的节点。因为根节点是最小的节点,那么我们只需要找到第一个比根节点大的节点就行了。
递归分为三步,接下来就按照这三步来思考问题
第一步:挖掘出相同的子问题 (关系到具体函数头的设计)
第二步:只关心具体子问题做了什么 (关系到具体函数体怎么写,是一个宏观的过程)
第三步:找到递归的出口,防止死递归 (关系到如何跳出递归)
2.1 相同的子问题(函数头设计)
相同的子问题:找二叉树的第二小的节点就是找二叉树左子树的第二小节点和右子树第二小节点。
根据上面的分析,这里需要传递的参数包括三个:
- T
reeNode* root
二叉树 - 根节点的值
int rootvalue
- 第二小的节点的值
int& ans
下面是leetcode给的函数头:
int findSecondMinimumValue(TreeNode* root) {
}
传递一个二叉树进来,最后返回二叉树中第二小的节点。
我们自己设计的函数头如下:
void dfs(TreeNode* root, int& ans, int rootvalue)
{
}
解释:
1.为什么ans传递引用而rootvalue不传递引用?
因为rootvalue表示的是整个二叉树根节点的值,也就是最小值,这个值是不会改变的,所以直接传递,不需要传递引用。而ans表示第二小的节点的值,这个值会根据不断的递归而改变,直到最终确定,所以要传递引用。
2.返回值为什么是void?
因为答案存储在ans中,不需要返回值
2.2 具体的子问题做了什么(函数体的实现)
根据之前的分析,具体的子问题做的事情:
1.判断当前节点的值是否是第一个大于rootvalue的值,如果是就更新给ans
2.判断左子树和右子树
这里有一个小细节:
当当前节点的值大于ans
时,说明从该节点开始的后面的所有节点都大于ans
(因为该节点的值是这颗子树中最小的)
正是因为这样的原因,如果当前节点的值大于ans
时,就不需要往后递归了。做到了剪枝。
函数的实现:
void dfs(TreeNode* root, int& ans, int rootvalue)
{
//递归的出口
if (root == nullptr)
return;
//剪枝
if (ans != -1 && root->val >= ans)
return;
if (root->val > rootvalue)
ans = root->val;
dfs(root->left, ans, rootvalue);
dfs(root->right, ans, rootvalue);
}
总结
class Solution {
public:
void dfs(TreeNode* root, int& ans, int rootvalue)
{
if (root == nullptr)
return;
//剪枝
if (ans != -1 && root->val >= ans)
return;
if (root->val > rootvalue)
ans = root->val;
dfs(root->left, ans, rootvalue);
dfs(root->right, ans, rootvalue);
}
int findSecondMinimumValue(TreeNode* root) {
int ans = -1;
//根节点的值是不会修改的,也是最小的
int rootvalue = root->val;
dfs(root, ans, rootvalue);
return ans;
}
1. 相同的子问题:找二叉树的第二小的节点就是找二叉树左子树的第二小节点和右子树第二小节点。
2. 具体子问题做了什么:判断当前节点的值是否是第一个大于rootvalue的值,如果是就更新给ans.判断左子树和右子树
3. 递归的出口:当前节点为空。