• 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) );
        }
    };
    

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

    1. 从上而下,当走到叶子节点的时候,检测是否为目标值
    干啥啥不行,吃饭第一名
  • 相关阅读:
    华为面试
    多线程下的单例模式
    乐观锁的一种实现方式——CAS
    乐观锁和悲观锁
    数据库行锁,表锁
    常用的设计模式
    grunt-contrib-watch 实时监测文件状态
    grunt-contrib-compass 编译sass
    grunt的安装及使用
    dede 调取二级三级菜单栏目
  • 原文地址:https://www.cnblogs.com/jiangxinyu1/p/12284978.html
Copyright © 2020-2023  润新知