LeetCode 树(3)

题目

4. 递归求解

617 合并二叉树

合并两个二叉树。

判断各个节点是否存在,全部合并到一棵树上即可。

class Solution {
public:
    TreeNode *mergeTrees(TreeNode *t1, TreeNode *t2) {
        if (!t1 && !t2)
            return nullptr;
        else if (!t1)
            return t2;
        else if (!t2)
            return t1;
        t1->val += t2->val;
        t1->left = mergeTrees(t1->left, t2->left);
        t1->right = mergeTrees(t1->right, t2->right);
        return t1;
    }
};

226 翻转二叉树

翻转一个二叉树。

先将左右子树分别翻转,再交换两者的位置。

class Solution {
public:
    TreeNode *invertTree(TreeNode *root) {
        if (!root)
            return nullptr;
        TreeNode *left = invertTree(root->left), *right = invertTree(root->right);
        root->right = left;
        root->left = right;
        return root;
    }
};

104 二叉树的最大深度

找出一个二叉树的最大深度。

每层深度为 1,加上左右子树中更大的深度即为最大深度。

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

965 单值二叉树

判断一个二叉树是否是一个单值二叉树。

判断每个节点与其左右节点的值是否相同即可。

class Solution {
public:
    bool isUnivalTree(TreeNode *root) {
        if (!root)
            return true;
        return (root->left ? root->val == root->left->val : true) && (root->right ? root->val == root->right->val : true) && isUnivalTree(root->left) && isUnivalTree(root->right);
    }
};

559 N叉树的最大深度

找到一个 N 叉树的最大深度。

每层深度为 1,加上其所有子树中最大的深度即为最大深度。

class Solution {
public:
    int maxDepth(Node* root) {
        if (!root)
            return 0;
        int depth = 0;
        for (auto &c:root->children)
            depth = max(depth, maxDepth(c));
        return 1 + depth;
    }
};

563 二叉树的坡度

计算一个二叉树的坡度。

对于每个节点,计算其左子树和右子树的和,将其差的绝对值加到总的坡度上,再返回左子树,右子树,与自己的值的和,递归调用即可。

class Solution {
    int res;
public:
    int findTilt(TreeNode *root) {
        res = 0;
        CalcTilt(root);
        return res;
    }

    int CalcTilt(TreeNode *node) {
        if (!node)
            return 0;
        int left = CalcTilt(node->left);
        int right = CalcTilt(node->right);
        res += abs(left - right);
        return node->val + left + right;
    }
};

508 出现次数最多的子树元素和

找出一个二叉树中出现次数最多的子树元素和。

计算出一个节点的左子树和右子树的子树元素和,加上自身的值就是一个完整的子树元素和,递归调用计算所有的节点并计数即可。

class Solution {
    unordered_map<int, int> count;
public:
    vector<int> findFrequentTreeSum(TreeNode *root) {
        vector<int> res;
        count = unordered_map<int, int>();
        Traverse(root);
        int n = 0;
        for (auto &c:count) {
            if (c.second > n) {
                n = c.second;
                res.clear();
                res.push_back(c.first);
            } else if (c.second == n)
                res.push_back(c.first);
        }
        return res;
    }

    int Traverse(TreeNode *root) {
        if (!root)
            return 0;
        int val = Traverse(root->left) + Traverse(root->right) + root->val;
        ++count[val];
        return val;
    }
};

5. 栈求解

623 在二叉树中增加一行

给一个二叉树,在第 d 层追加一行值为 v 的节点。

用一个栈保存一层的所有节点,逐层遍历即可。注意 d = 1 时要单独处理。

class Solution {
public:
    TreeNode *addOneRow(TreeNode *root, int v, int d) {
        if (!root)
            return nullptr;
        if (d == 1) {
            TreeNode *new_root = new TreeNode(v);
            new_root->left = root;
            return new_root;
        }
        queue<TreeNode *> q;
        q.push(root);
        int depth = 1, n = 1;
        while (!q.empty() && depth < d) {
            for (int i = 0; i < n; ++i) {
                TreeNode *node = q.front();
                q.pop();
                if (depth == d - 1) {
                    TreeNode *left = node->left, *right = node->right;
                    node->left = new TreeNode(v);
                    node->right = new TreeNode(v);
                    node->left->left = left;
                    node->right->right = right;
                }
                if (node->left)
                    q.push(node->left);
                if (node->right)
                    q.push(node->right);
            }
            ++depth;
            n = q.size();
        }
        return root;
    }
};

6. 找节点

1123. 最深叶节点的最近公共祖先

找到一个二叉树最深的叶节点的最近公共祖先。

可以先用层序遍历找到二叉树的深度,再通过一次递归找到所有叶节点的公共祖先。

class Solution {
    TreeNode *res;
    int lvl;
public:
    TreeNode *lcaDeepestLeaves(TreeNode *root) {
        if (!root)
            return nullptr;
        res = nullptr;
        lvl = 0;
        queue<TreeNode *> nodes;
        nodes.push(root);
        int n = 1;
        while (!nodes.empty()) {
            for (int i = 0; i < n; ++i) {
                TreeNode *node = nodes.front();
                nodes.pop();
                if (node->left) nodes.push(node->left);
                if (node->right) nodes.push(node->right);
            }
            ++lvl;
            n = nodes.size();
        }
        FindLCA(root, 1);
        return res;
    }

    bool FindLCA(TreeNode *root, int l) {
        if (root && l == lvl) {
            res = root;
            return true;
        } else if (!root)
            return false;
        bool left = FindLCA(root->left, l + 1), right = FindLCA(root->right, l + 1);
        if (left && right)
            res = root;
        return left || right;
    }
};

但实际上我们并不需要知道这棵树的深度,只需要知道最深的节点即是叶节点,并且如果一个节点的左子树和右子树的最深节点的深度相同,那么这个节点就是他们的最近公共祖先,返回这个节点即可。

class Solution {
public:
    TreeNode *lcaDeepestLeaves(TreeNode *root) {
        return FindLCA(root).first;
    }

    pair<TreeNode *, int> FindLCA(TreeNode *root) {
        if (!root)
            return pair<TreeNode *, int>(nullptr, 0);
        auto left = FindLCA(root->left), right = FindLCA(root->right);
        if (left.second > right.second)
            return pair<TreeNode *, int>(left.first, left.second + 1);
        if (left.second < right.second)
            return pair<TreeNode *, int>(right.first, right.second + 1);
        return pair<TreeNode *, int>(root, left.second + 1);
    }
}