笔记84:关于递归法的一些感悟

第一部分:


题目1:二叉树的前序遍历

链接:. - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void DFS_pre(TreeNode* ptr, vector<int>& result) {
        if(ptr == nullptr) return;
        result.push_back(ptr->val);
        DFS_pre(ptr->left, result);
        DFS_pre(ptr->right, result);
    }

    vector<int> preorderTraversal(TreeNode* root) {
        //个人尝试:递归求解
        //前序:中左右
        vector<int> result;
        DFS_pre(root, result);
        return result;
    }
};

补充说明:对于二叉树的前中后续遍历,传入的指针参数只有一个


题目2:对称二叉树

链接:. - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool Compare_Left_And_Right(TreeNode* left, TreeNode* right) {
        //终止条件
        if(left == nullptr && right == nullptr) return true;
        if(left != nullptr && right == nullptr) return false;
        if(left == nullptr && right != nullptr) return false;
        if(left->val != right->val) return false;                           //比较中侧(这四个终止条件,都是对中侧的比较)

        bool outside = Compare_Left_And_Right(left->left, right->right);    //比较外侧
        bool inside = Compare_Left_And_Right(left->right, right->left);     //比较内侧

        return (outside && inside);
    }

    bool isSymmetric(TreeNode* root) {
        //自己尝试:递归法
        if(root == nullptr) return true;
        return Compare_Left_And_Right(root->left, root->right);
    }
};

补充:对于这个题,递归函数体内部传入了两个指针参数


感悟:在做这个题之前,我一直以为递归算法只能指定一个遍历方向,但其实递归非常的强大,可以指定多个方向同时遍历;

(1)如果递归函数体只能传入一个指针参数,那么递归只能往同一个方向遍历;例如对二叉树前中后序的遍历,都是只有一个参数的递归,因此递归函数体的内部主逻辑中,只有对这一个参数的处理,而在递归函数体内部再一次调用递归函数体时,也是只能传入一个参数,那么这就导致我们只能往一个方向遍历;比如上个递归体中参数是左分支,那么当前这个递归体传入的参数必须是左分支的左分支,即都是往左进行的遍历;(否则一会往左递归,一会往右递归,就乱套了,没有了共同规则的约束)

(2)如果递归函数体可以传入两个指针参数,那么递归就可以往两个方向同时进行;例如对称二叉树这个题,我们想左子树往左遍历,右子树往右遍历,那么递归的参数必须有俩,一个遵循往左走, 一个遵循往右走,即两个参数往两个不同的方向走;

图解:

前序遍历(统一往左侧遍历)
对称二叉树(双向遍历)

a

a

a

a

第二部分:


题目1:完全二叉树的节点个数

链接:. - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int countNodes(TreeNode* root) {
        //官方解法:递归实现(先找出完全二叉树中的满二叉树,再计算节点数量)

        //终止条件:
        if(root == nullptr) return 0;

        //函数体:
        TreeNode* left = root->left;    //获得左右子树根节点
        TreeNode* right = root->right;
        int leftDepth = 1;              //这里初始为0是有目的的,为了下面求指数方便
        int rightDepth = 1;
        while(left != nullptr) {        //求左子树深度
            left = left->left;
            leftDepth++;
        }
        leftDepth--;
        while(right != nullptr) {       //求右子树深度
            right = right->right;
            rightDepth++;
        }
        rightDepth--;

        //返回值:
        if(leftDepth == rightDepth) {   //注意:2<<1 相当于 2^2,所以 leftDepth 初始为0
            return (2 << leftDepth) - 1;
        }
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};

感悟:我以前写递归算法虽然也是分成三部分(终止条件+函数体+返回值),但是对递归函数体的调用我都是写在函数体中的,而这个题是全部写在返回值部分;

这个题的递归稍微有点怪,他并不是普通递归那样先走到底,再往上回溯;他是一层一层的从上往下递归(通过函数体实现),然后再一层一层从下往上递归(通过递归实现);


a

a

a

a

第三部分:


题目1:验证二叉搜索树

链接:. - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* pre = nullptr;
    
    bool Identify_Tree(TreeNode* ptr) {
        //终止条件:
        if(ptr == nullptr) return true;

        //函数体:
        //(1)进入一棵新子树的时候,需要立刻定位到该子树的最左下角元素,这个就是将与pre指向的元素进行对比的元素;
        bool flag_left = Identify_Tree(ptr->left);
        //(2)进行对比;
        if(pre != nullptr && pre->val >= ptr->val) return false;
        //(3)对比完成后更改pre的指向,为当前元素
        pre = ptr;
        //(4)进入新子树的根节点ptr->right,找到新子树的最左下角元素
        bool flag_right = Identify_Tree(ptr->right);

        //返回值:
        return (flag_left && flag_right);
    }

    bool isValidBST(TreeNode* root) {
        //自己尝试:递归法
        //注:自己尝试一下官方的思路,即引入一个指针pre指向上一个元素(需要跟当前元素比较的元素)
        //思路:指针pre只指向根节点
        return Identify_Tree(root);
    }
};

题目2:二叉搜索树的最小绝对差

链接:. - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* pre = nullptr;
    int min = INT_MAX;

    void Get_Min_Dif(TreeNode* ptr) {
        //终止条件:
        if(ptr == nullptr) return;

        //函数体:
        Get_Min_Dif(ptr->left);
        if(pre != nullptr) min = min > abs(pre->val - ptr->val) ? abs(pre->val - ptr->val) : min;
        pre = ptr;
        Get_Min_Dif(ptr->right);

        //返回值:
        return;
    }

    int getMinimumDifference(TreeNode* root) {
        //自己尝试:递归法
        //思路:因为是求最小绝对差值,因此必定是二叉搜索树中俩相邻(指中序遍历的顺序访问节点的顺序)点之间的
        //      差值,我们可以用上一题的方法来写这一题;定义一个pre指针指向上一次递归访问的节点;
        Get_Min_Dif(root);
        return min;
    }
};

感悟:这个题的解法引入了额外的指针,这样就解决了递归的时候想对比相隔的很远的两个递归体之间的值的问题;


  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值