基本题目

226. 翻转二叉树

递归

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

101. 对称二叉树

递归

class Solution {
public:
    bool isSymmetric(TreeNode *root1, TreeNode *root2) {
        if (!root1 && !root2) return true;
        if (!root1 || !root2 || root1->val != root2->val) return false;
        return isSymmetric(root1->left, root2->right) && isSymmetric(root1->right, root2->left);
    }

    bool isSymmetric(TreeNode* root) {
        if (!root) return true;
        return isSymmetric(root->left, root->right);
    }
};

迭代:可以使用队列来实现逐层遍历,并通过控制入队顺序来实现功能

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if (!root) return true;
        queue<TreeNode *> q;
        q.push(root->left);
        q.push(root->right);

        TreeNode *tmp1, *tmp2;
        while (q.size() >= 2) {
            tmp1 = q.front();
            q.pop();
            tmp2 = q.front();
            q.pop();
            if (!tmp1 && !tmp2) continue;
            else if (!tmp1 || !tmp2 || tmp1->val != tmp2->val) return false;
            q.push(tmp1->left);
            q.push(tmp2->right);
            q.push(tmp1->right);
            q.push(tmp2->left);
        }

        return q.empty();
    }
};

222. 完全二叉树的节点个数

递归

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

二分查找+节点总数的二进制表示与路径的关系

class Solution {
public:
    bool exists(TreeNode *root, int height, int size) {
        int mask = 1 << (height - 2);
        while (mask > 0) {
            root = (size & mask) ? root->right : root->left;
            mask >>= 1;
        }
        return root;
    }

    int countNodes(TreeNode* root) {
        if (!root) return 0;
        int height = 0;
        TreeNode *tmp = root;
        while (tmp) {
            height++;
            tmp = tmp->left;
        }

        int lo = 1 << (height - 1), hi = (1 << height) - 1, mi;
        while (lo < hi) {
            mi = (lo + hi + 1) / 2;
            if (exists(root, height, mi)) lo = mi;
            else hi = mi - 1;
        }
        return lo;
    }
};

110. 平衡二叉树

递归+传递高度信息

class Solution {
public:
    int balancedHeight(TreeNode *root) {
        if (!root) return 0;
        int h1, h2;
        if ((h1 = balancedHeight(root->left)) < 0 || (h2 = balancedHeight(root->right)) < 0) return -1;
        if (abs(h1 - h2) > 1) return -1;
        return max(h1, h2) + 1;
    }

    bool isBalanced(TreeNode* root) {
        return balancedHeight(root) >= 0;
    }
};

257. 二叉树的所有路径

DFS 递归/栈

class Solution {
public:
    void getPaths(vector<string> &result, string path, TreeNode *node) {
        path += to_string(node->val);
        if (!node->left && !node->right) result.push_back(path);
        else {
            if (node->left) getPaths(result, path + "->", node->left);
            if (node->right) getPaths(result, path + "->", node->right);
        }
    }

    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        getPaths(result, "", root);
        return result;
    }
};
class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        stack<string> paths;
        stack<TreeNode *> st;
        paths.push("");
        st.push(root);

        TreeNode *tmp;
        string prev;
        while (!st.empty()) {
            tmp = st.top();
            st.pop();
            prev = paths.top();
            paths.pop();

            prev += ("->" + to_string(tmp->val));
            if (tmp->right) {
                st.push(tmp->right);
                paths.push(prev);
            }
            if (tmp->left) {
                st.push(tmp->left);
                paths.push(prev);
            }

            if (!tmp->left && !tmp->right) {
                result.push_back(prev.substr(2));
            }
        }
        return result;
    }
};

404. 左叶子之和

DFS 递归

class Solution {
public:
    int sumOfLeftLeaves(TreeNode *root, bool leftChild) {
        if (!root) return 0;
        if (!root->left && !root->right) return leftChild ? root->val : 0;
        return sumOfLeftLeaves(root->left, true) + sumOfLeftLeaves(root->right, false);
    }

    int sumOfLeftLeaves(TreeNode* root) {
        return sumOfLeftLeaves(root, false);
    }
};

513. 找树左下角的值

DFS 递归/BFS 迭代

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        int result;
        queue<TreeNode *> q;
        q.push(root);
        TreeNode *tmp;

        while (!q.empty()) {
            result = q.front()->val;
            int n = q.size();
            for (int i = 0; i < n; i++) {
                tmp = q.front();
                q.pop();
                if (tmp->left) q.push(tmp->left);
                if (tmp->right) q.push(tmp->right);
            }
        }

        return result;
    }
};

只需要找一个树节点,这个节点应当是 BFS 遍历(从右到左)的最后一个节点。无需逐层

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        int result;
        queue<TreeNode *> q;
        q.push(root);
        TreeNode *tmp;

        while (!q.empty()) {
            tmp = q.front();
            q.pop();
            if (!tmp) continue;
            q.push(tmp->right);
            q.push(tmp->left);
            result = tmp->val;
        }

        return result;
    }
};

112. 路径总和

DFS 递归/BFS 迭代

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

106. 从中序与后序遍历序列构造二叉树

递归+数组元素位置的反向映射

class Solution {
private:
    unordered_map<int, int> inIndex;

public:
    TreeNode *buildTree(vector<int>& inorder, vector<int>& postorder, int i, int j, int size) {
        if (!size) return nullptr;
        int val = postorder[j + size - 1];
        int index = inIndex[val];
        return new TreeNode(val, buildTree(inorder, postorder, i, j, index - i), 
                                 buildTree(inorder, postorder, index + 1, j + index - i, i + size - index - 1));
    }

    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        for (int i = 0; i < inorder.size(); i++) inIndex[inorder[i]] = i;
        return buildTree(inorder, postorder, 0, 0, inorder.size());
    }
};

可以用巧妙的迭代+栈方法解答: 力扣解答

654. 最大二叉树

递归

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums, int lo, int hi) {
        if (hi <= lo) return nullptr;
        int maximum = INT_MIN, maxId = -1;
        for (int i = lo; i < hi; i++) {
            if (nums[i] > maximum) {
                maxId = i;
                maximum = nums[i];
            }
        }
        return new TreeNode(nums[maxId], constructMaximumBinaryTree(nums, lo, maxId), constructMaximumBinaryTree(nums, maxId + 1, hi));
    }

    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return constructMaximumBinaryTree(nums, 0, nums.size());
    }
};

可以使用单调栈来避免多次查找最大元素:维护一个递减栈,每次出现比栈顶更大的元素,则将那些更小的元素弹出,作为新节点的左子树

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        stack<TreeNode *> s;
        TreeNode *tmp;

        for (const int n : nums) {
            tmp = nullptr;
            while (!s.empty() && s.top()->val < n) {
                s.top()->right = tmp;
                tmp = s.top();
                s.pop();
            }
            tmp = new TreeNode(n, tmp, nullptr);
            s.push(tmp);
        }

        tmp = nullptr;
        while (!s.empty()) {
            s.top()->right = tmp;
            tmp = s.top();
            s.pop();
        }
        return tmp;
    }
};

617. 合并二叉树

DFS 递归/BFS 迭代

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if (!root1) return root2;
        if (!root2) return root1;
        root1->val += root2->val;
        root1->left = mergeTrees(root1->left, root2->left);
        root1->right = mergeTrees(root1->right, root2->right);
        return root1;
    }
};

拓展练习

100. 相同的树

递归

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if (!p && !q) return true;
        else if (!p || !q || p->val != q->val) return false;
        return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
    }
};

572. 另一个树的子树

递归

class Solution {
public:
    bool isEqual(TreeNode *node1, TreeNode *node2) {
        if (!node1 && !node2) return true;
        else if (!node1 || !node2 || node1->val != node2->val) return false;
        return isEqual(node1->left, node2->left) && isEqual(node1->right, node2->right);
    }

    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        if (!root) return false;
        if (isEqual(root, subRoot)) return true;
        return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
    }
};

如果在树遍历的过程中加入 NULL 节点,那么前序遍历的结果与树结构一一对应。后序遍历的结果也满足这个性质,中序遍历不满足

class Solution {
public:
    void preorderTraverse(vector<int> &v, TreeNode *node) {
        if (!node) {
            v.push_back(INT_MIN);
            return;
        }
        v.push_back(node->val);
        preorderTraverse(v, node->left);
        preorderTraverse(v, node->right);
    }

    void constructNext(vector<int> &next, const vector<int> &pattern) {
        int m = pattern.size();
        for (int i = 1; i < m; i++) {
            int tmp = next[i - 1];
            while (tmp > 0 && pattern[i] != pattern[tmp]) tmp = next[tmp - 1];
            if (pattern[i] == pattern[tmp]) next[i] = tmp + 1;
            else next[i] = 0;
        }
    }

    bool kmpMatch(const vector<int> &source, const vector<int> &pattern) {
        int n = source.size(), m = pattern.size();
        vector<int> next(m, 0);
        constructNext(next, pattern);
        int i = 0, j = 0;
        while (i < n && j < m) {
            if (source[i] == pattern[j]) {
                i++;
                j++;
            }
            else if (j > 0) {
                j = next[j - 1];
            }
            else {
                i++;
            }
        }
        return j == m;
    }

    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        vector<int> preorder1, preorder2;
        preorderTraverse(preorder1, root);
        preorderTraverse(preorder2, subRoot);
        return kmpMatch(preorder1, preorder2);
    }
};

113. 路径总和 II

DFS 递归+路径回溯

class Solution {
public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<vector<int>> result;
        vector<int> path;
        pathSumFinder(result, path, root, targetSum);
        return result;
    }

    void pathSumFinder(vector<vector<int>> &result, vector<int> &path, TreeNode *root, int target) {
        if (!root) return;
        path.push_back(root->val);
        target -= root->val;

        if (!root->left && !root->right) {
            if (target == 0) result.push_back(path);
            path.pop_back();
            return;
        }

        pathSumFinder(result, path, root->left, target);
        pathSumFinder(result, path, root->right, target);
        path.pop_back();
    }
};

除了路径回溯,还可以使用哈希表的方式存储逆序路径,用于路径输出

105. 从前序与中序遍历序列构造二叉树

递归+数组元素位置的反向映射。与 106 类似,可以用特殊的迭代方式完成

class Solution {
private:
    unordered_map<int, int> inIndex;

public:
    TreeNode *buildTree(vector<int>& preorder, vector<int>& inorder, int i, int j, int size) {
        if (!size) return nullptr;
        int val = preorder[i];
        int index = inIndex[val];
        return new TreeNode(val, buildTree(preorder, inorder, i + 1, j, index - j), 
                                 buildTree(preorder, inorder, i + index + 1 - j, index + 1, j + size - index - 1));
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        for (int j = 0; j < inorder.size(); j++) inIndex[inorder[j]] = j;
        return buildTree(preorder, inorder, 0, 0, inorder.size());
    }
};