leetcode经典题目(11)--树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
1. 树的深度(NO.104)

题目描述:给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
解题思路:使用递归。若根节点非空,则深度等于左子树深度和右子树深度的较大值加1.

class Solution {
    
    
public:
    int maxDepth(TreeNode* root) {
    
    
        if (root == nullptr)
            return 0;
        return max(maxDepth(root->left),maxDepth(root->right)) + 1;       
    }
};

求二叉树的最小深度

class Solution {
    
    
public:
    int minDepth(TreeNode* root) {
    
    
        if (root == nullptr)
            return 0;
        if (root->left == nullptr && root->right != nullptr)
            return minDepth(root->right) + 1;
        if (root->left != nullptr && root->right == nullptr)
            return minDepth(root->left) + 1;
        return min(minDepth(root->left),minDepth(root->right)) + 1;      
    }
};
2. 平衡二叉树(NO.110)

题目描述:给定一个二叉树,判断它是否是高度平衡的二叉树。一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
解题思路:使用一个全局变量res记录所有节点是否都平衡。计算树的深度时,如果一个节点的左右子树高度相差超过1,则令res=false。

class Solution {
    
    
public:
    bool res = true;//全局变量
    int depth(TreeNode* root){
    
    
        if (root == nullptr)
            return 0;
        int l = depth(root->left);
        int r = depth(root->right);
        if (l - r > 1 || l - r < -1)//左右子树高度相差超过1
            res = false;
        return max(l,r) + 1;   
    }
    bool isBalanced(TreeNode* root) {
    
    
        depth(root);
        return res;
    }
};
3. 两节点的最短路径(NO.543)

题目描述:给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
解题思路:以一个分支节点为中心的直径长度为该节点左右子树的高度之和。定义一个全局变量记录最大路径长度d,使用递归的方式计算树的高度,同时更新d。

class Solution {
    
    
public:
    int d = 0;
    int depth(TreeNode* root){
    
    
        if (root == nullptr)
            return 0;
        int l = depth(root->left);
        int r = depth(root->right);
        d = max(d,l+r);//更新d
        return max(l,r) + 1;
    }
    int diameterOfBinaryTree(TreeNode* root) {
    
    
        depth(root);
        return d;
    }
};
4. 翻转一棵二叉树(NO.226)

解题思路:采用递归的方法,将一个根节点的左右子树交换。

class Solution {
    
    
public:
    TreeNode* invertTree(TreeNode* root) {
    
    
        if (root == nullptr)
            return nullptr;
        TreeNode* tmp = root->left;//保存左子树
        root->left = invertTree(root->right);//交换左右子树的位置
        root->right = invertTree(tmp);
        return root;
    }
};
5. 归并两棵树(NO.617)

题目描述:给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则将不为 NULL 的节点直接作为新二叉树的节点。

class Solution {
    
    
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
    
    
        if (t1 == nullptr && t2 == nullptr)
            return nullptr;
        else if (t1 == nullptr)
            return t2;
        else if (t2 == nullptr)
            return t1;
        else{
    
    
            TreeNode* root = new TreeNode;
            root->val = t1->val + t2->val;
            root->left = mergeTrees(t1->left,t2->left);
            root->right = mergeTrees(t1->right,t2->right);
            return root;
        } 
    }
};
6. 判断路径和是否等于一个数(NO.112)

题目描述:给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
解题思路:采用递归的思想。如果根节点为空,返回false,若非空,判断左右子树中是否有一个满足路径和为sum减去根节点的值,递归出口为叶子节点值是否满足要求。

class Solution {
    
    
public:
    bool hasPathSum(TreeNode* root, int sum) {
    
    
        if (root == nullptr)
            return false;
        if (root->left == nullptr && root->right == nullptr)
            return root->val == sum;
        return hasPathSum(root->left,sum-(root->val)) 
                || hasPathSum(root->right,sum-(root->val));

    }
};
7. 统计路径和等于一个数的路径数量(NO.437)

题目描述:给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
解题思路:因为路径不必从根节点开始,所以要考虑以每个节点为起始节点的路径数量。设置一个全局变量记录路径数。定义函数pathSumWithRoot(TreeNode* root, int sum)判断以root为起始节点的路径,如果找到一条,就让cnt加1。然后在pathSum函数中,以root为起始节点,并递归计算左右子树。

class Solution {
    
    
public:
    int cnt = 0;
    int pathSum(TreeNode* root, int sum) {
    
    
        if (root == nullptr)
            return 0;
        pathSumWithRoot(root,sum);//以root为起始节点
        pathSum(root->left,sum);//递归左子树
        pathSum(root->right,sum);//递归右子树
        return cnt;
    }
    void pathSumWithRoot(TreeNode* root, int sum){
    
    
        if (root == nullptr)
            return;
        if (root->val == sum)//找到一条路径
            cnt++;
        pathSumWithRoot(root->left,sum-root->val); 
        pathSumWithRoot(root->right,sum-root->val);     
    }
};
8. 子树(NO.572)

题目描述:给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
解题思路:s要么等于t,s的左子树等于t;s的右子树等于t。

class Solution {
    
    
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
    
    
        if (s == nullptr)//都遍历完了,还没匹配上,返回false
            return false;
        return isSameTree(s,t) ||isSubtree(s->left,t) || isSubtree(s->right,t);
        
    }
    bool isSameTree(TreeNode* s, TreeNode* t){
    
    //判断两棵树是否相同
        if (s == nullptr && t == nullptr)
            return true;
        if (s == nullptr || t == nullptr)
            return false;
        if (s->val != t->val)
            return false;
        return isSameTree(s->left,t->left) && isSameTree(s->right,t->right);
    }
};
9. 对称二叉树(NO.101)

题目描述:给定一个二叉树,检查它是否是镜像对称的。

class Solution {
    
    
public:
    bool isSymmetric(TreeNode* root) {
    
    
        if (root == nullptr)//根节点为空
            return true;
        return isSymmetric2(root->left,root->right);//根节点非空,判断左右子树是否相互对称
    }
    bool isSymmetric2(TreeNode* t1, TreeNode* t2){
    
    //判断两棵树是否对称
        if (t1 == nullptr && t2 == nullptr)
            return true;
        if (t1 == nullptr || t2 == nullptr)
            return false;
        if (t1->val != t2->val)
            return false;
        return isSymmetric2(t1->left,t2->right) && isSymmetric2(t1->right,t2->left);
    }
};
10. 统计左叶子节点的和(NO.404)

题目描述:计算给定二叉树的所有左叶子之和。

class Solution {
    
    
public:  
    int sumOfLeftLeaves(TreeNode* root) {
    
    
        if (root == nullptr)
            return 0;
        if (root->left != nullptr && root->left->left == nullptr 
            && root->left->right == nullptr)//左叶子节点
            return root->left->val + sumOfLeftLeaves(root->right);//左叶子节点值加上右子树的递归结果
        return sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);//继续递归
    }
};
11. 打家劫舍(间隔遍历)(NO.337)

题目描述:在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
解题思路:对于一个以 node 为根节点的二叉树而言,如果尝试偷取 node 节点,那么势必不能偷取其左右子节点,然后继续尝试偷取其左右子节点的左右子节点。如果不偷取该节点,那么只能尝试偷取其左右子节点。比较两种方式的结果,谁大取谁。
类似于斐波那契数列的递归,在求root的孩子结点的解的时候会把下面的结点的解全算一遍,把所有的结点的解都存起来的话再求孩子的孩子就相当于查表一样了,减少了重复计算。

class Solution {
    
    
    unordered_map<TreeNode*,int> sums;
public:
    int rob(TreeNode* root) {
    
    
        if (root == nullptr)
            return 0;
        if (sums.count(root)) 
            return sums[root];
        int val1 = root->val;//偷取root节点
        if (root->left != nullptr)//偷取root节点左右节点的子节点
            val1 += rob(root->left->left) + rob(root->left->right);
        if (root->right != nullptr)
            val1 += rob(root->right->left) + rob(root->right->right);
        int val2 = rob(root->left) + rob(root->right);//不偷root节点,偷其两个子节点
        sums[root] = max(val1, val2);
        return max(val1,val2);
    }
};
12. 二叉树的所有路径(NO.257)

题目描述:给定一个二叉树,返回所有从根节点到叶子节点的路径。
解题思路:使用深度优先遍历。

class Solution {
    
    
public:
    vector<string> binaryTreePaths(TreeNode* root) {
    
    
        if (root == nullptr)
            return vector<string>();
        string path;
        dfs(root, path);
        return res;
    }
private:
    vector<string> res;
    void dfs(TreeNode* root, string path){
    
    
        path += to_string(root->val);

        if (root->left == nullptr && root->right == nullptr){
    
    
            res.push_back(path);
            return;
        }

        if (root->left)
            dfs(root->left, path + "->");
        if (root->right)
            dfs(root->right, path + "->");
    }
};

猜你喜欢

转载自blog.csdn.net/qq_42820853/article/details/107528391
今日推荐