二叉樹高頻題(下)

n1ce2cv發表於2024-09-30

二叉樹高頻題(下)

236. 二叉樹的最近公共祖先

using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;

    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    // 前提:節點的值唯一,p、q都在二叉樹中
    TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {
        // 如果 p 和 q 中有等於 root 的,那麼它們的最近公共祖先即為 root(一個節點也可以是它自己的祖先)
        if (root == nullptr || root == p || root == q) return root;

        // 遞迴遍歷左子樹,只要在左子樹中找到了 p 或 q,則先找到誰就返回誰
        TreeNode *left = lowestCommonAncestor(root->left, p, q);
        // 遞迴遍歷右子樹,只要在右子樹中找到了 p 或 q,則先找到誰就返回誰
        TreeNode *right = lowestCommonAncestor(root->right, p, q);

        // 當 left 和 right 均不為空時,說明 p、q 節點分別在 root 異側, 最近公共祖先即為 root
        if (left != nullptr && right != nullptr) return root;
        // 如果在一側的子樹中 p 和 q 都找不到,則 p 和 q 一定都在另一側的子樹中,另一側中先遍歷到的那個就是最近公共祖先
        return left == nullptr ? right : left;
    }
};

235. 二叉搜尋樹的最近公共祖先

  • 利用搜尋二叉樹特性
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;

    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {
        if (root == nullptr || root == p || root == q) return root;
        // 都比當前根節點的值小,說明都在左子樹
        if (root->val > p->val && root->val > q->val)
            return lowestCommonAncestor(root->left, p, q);
        // 都比當前根節點的值大,說明都在右子樹
        if (root->val < p->val && root->val < q->val)
            return lowestCommonAncestor(root->right, p, q);
        // 在兩側,當前的根節點就是最近公共祖先
        return root;
    }
};
  • 沒有利用搜尋二叉樹特性的做法
class Solution {
public:
    TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {
        if (root == nullptr || root == p || root == q) return root;
        TreeNode *left = lowestCommonAncestor(root->left, p, q);
        TreeNode *right = lowestCommonAncestor(root->right, p, q);
        if (left == nullptr) return right;
        if (right == nullptr) return left;
        return root;
    }
};

113. 路徑總和 II

#include <vector>

using namespace std;

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:
    vector<vector<int>> res;
    vector<int> path;
    int target;

    void dfs(TreeNode *root, int sum) {
        if (root == nullptr) return;
        sum += root->val;
        if (root->left == nullptr && root->right == nullptr && sum == target) {
            path.emplace_back(root->val);
            res.emplace_back(vector<int>(path));
            // 回退路徑
            path.erase(end(path));
            return;
        }
        path.emplace_back(root->val);
        if (root->left != nullptr) dfs(root->left, sum);
        if (root->right != nullptr) dfs(root->right, sum);
        // 回退路徑
        path.erase(end(path));
    }

    vector<vector<int>> pathSum(TreeNode *root, int targetSum) {
        target = targetSum;
        dfs(root, 0);
        return res;
    }
};
class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    // 記錄節點對應的值在 path 中的下標
    unordered_map<TreeNode *, int> map;
    int target;

    void dfs(TreeNode *root, int sum) {
        if (root == nullptr) return;
        path.emplace_back(root->val);
        map.emplace(root, path.size() - 1);
        sum += root->val;
        if (root->left == nullptr && root->right == nullptr && sum == target) {
            res.emplace_back(vector<int>(path));
            return;
        }
        if (root->left != nullptr) {
            dfs(root->left, sum);
            // 回退路徑
            path.erase(begin(path) + map[root->left], end(path));
        }
        if (root->right != nullptr) {
            dfs(root->right, sum);
            // 回退路徑
            path.erase(begin(path) + map[root->right], end(path));
        }
    }

    vector<vector<int>> pathSum(TreeNode *root, int targetSum) {
        target = targetSum;
        dfs(root, 0);
        return res;
    }
};

110. 平衡二叉樹

#include <algorithm>

using namespace std;

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 balance;

    int depth(struct TreeNode *node) {
        if (!balance || node == nullptr) return 0;
        int left = depth(node->left);
        int right = depth(node->right);
        // 不平衡
        if (abs(left - right) > 1) balance = false;
        return max(left, right) + 1;
    }

    bool isBalanced(TreeNode *root) {
        balance = true;
        depth(root);
        return balance;
    }
};

98. 驗證二叉搜尋樹

using namespace std;

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;

    // 中序遍歷檢查是否嚴格遞增
    bool inorder(TreeNode *root) {
        if (root == nullptr) return true;
        if (!inorder(root->left)) return false;
        if (pre != nullptr && pre->val >= root->val) return false;
        pre = root;
        return inorder(root->right);
    }

    bool isValidBST(TreeNode *root) {
        pre = nullptr;
        return inorder(root);
    }
};
class Solution {
public:
    // 判斷每個節點是否在他應當在的範圍內
    bool dfs(struct TreeNode *root, long long min, long long max) {
        if (root == nullptr) return true;
        if (root->val <= min || root->val >= max) return false;
        return dfs(root->left, min, root->val) && dfs(root->right, root->val, max);
    }

    bool isValidBST(TreeNode *root) {
        return dfs(root, 0x8000000000000000, 0x7fffffffffffffff);
    }
};

669. 修剪二叉搜尋樹

using namespace std;

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 *trimBST(TreeNode *root, int low, int high) {
        if (root == nullptr) return nullptr;
        // 根節點超範圍,返回用修剪後的子樹,頂替根節點
        if (root->val < low) return trimBST(root->right, low, high);
        if (root->val > high) return trimBST(root->left, low, high);
        root->left = trimBST(root->left, low, high);
        root->right = trimBST(root->right, low, high);
        return root;
    }
};

337. 打家劫舍 III

  • 暴力遞迴
using namespace std;

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 rob(TreeNode *root) {
        if (root == nullptr) return 0;
        int money = root->val;
        if (root->left != nullptr)
            money += rob(root->left->left) + rob(root->left->right);
        if (root->right != nullptr)
            money += rob(root->right->left) + rob(root->right->right);
        // 返回偷 root 和不偷 root 的最大值
        return max(money, rob(root->left) + rob(root->right));
    }
};
  • 自上而下記憶化搜尋
class Solution {
public:
    // 記錄能偷的最大值
    unordered_map<TreeNode *, int> dp;

    int robInternal(TreeNode *root) {
        if (root == nullptr) return 0;
        // 如果有就返回
        if (dp.find(root) != dp.end()) return dp[root];
        int money = root->val;
        if (root->left != nullptr)
            money += (robInternal(root->left->left) + robInternal(root->left->right));
        if (root->right != nullptr)
            money += (robInternal(root->right->left) + robInternal(root->right->right));
        int result = max(money, robInternal(root->left) + robInternal(root->right));
        dp[root] = result;
        return result;
    }

    int rob(TreeNode *root) {
        return robInternal(root);
    }
};
class Solution {
public:
    int rob(TreeNode* root) {
        // 返回的是不偷和偷當前節點時,能偷的最大值
        vector<int> result = recursive(root);
        return max(result[0], result[1]);
    }

    vector<int> recursive(TreeNode* root) {
        if (root == nullptr) return {0, 0};
        vector<int> res(2);
        vector<int> left = recursive(root->left);
        vector<int> right = recursive(root->right);
        res[0] = max(left[0], left[1]) + max(right[0], right[1]);
        res[1] = left[0] + right[0] + root->val;
        return res;
    }
};

相關文章