1. 程式人生 > 實用技巧 >LeetCode基礎_樹_祖先系列

LeetCode基礎_樹_祖先系列

[235] 二叉搜尋樹的最近公共祖先
思路比較簡單,根據二叉搜尋樹性質,要找的node的val只要 p或q->val <= node->val <= q或p->val
class Solution {
public:
TreeNode *recurse(TreeNode *curr, TreeNode *p, TreeNode *q) {
if (curr->val < p->val && curr->val < q->val)
return recurse(curr->right, p, q);
else if (curr->val > p->val && curr->val > q->val)
return recurse(curr->left, p, q);
else
return curr;
}
TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {
return recurse(root, p, q);
}
};

[236] 二叉樹的最近公共祖先
簡單思路:On的空間複雜度來記錄根節點到p和q的路徑,遍歷從根到兩者的路徑一直到不同為止。
優化思路:遞迴,空間優化到O1
遇上題類似,只要左樹和右樹都存在p和q,即終止,否則繼續向左樹或右樹走
通過自上而下遞迴,進行優化後,無需重複遍歷。

這道題優化前為 先遞迴判斷條件 後遞迴往下找結果,
而優化後改變成 先遞迴往下找結果 後直接判斷條件並return。
程式碼如下:

class Solution {
public:
TreeNode *recurse(TreeNode *curr, TreeNode *p, TreeNode *q) {
if (!curr)
return nullptr; //可以縮寫,但為保證可讀性
if (curr == p || curr == q) //curr踩中某個點
return curr;

    TreeNode *left = recurse(curr->left, p, q);//在此步驟向下遞迴返回的就是符合條件的值
    TreeNode *right = recurse(curr->right, p, q);

    if (left && right) //左右都不為null,說明一邊有p 一邊有q,直接返回
        return curr;
    else if (left)   //只有一邊有p和q,另一邊沒有
        return left; //這裡經過了優化,因為上面的left已經遞迴過了,已經拿到了正確的結果
                     //return recurse(curr->left, p, q);//優化前
    else if (right)
        return right; //同上,優化,不做重複遞迴

    return nullptr;
}
TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {
    return recurse(root, p, q);
}

};

[572] 另一個樹的子樹

class Solution {
public:
bool isSameTree(TreeNode *s, TreeNode *t) {//遞迴判斷以當前節點為根的樹是否相同
if (!s && !t)
return true;
return s && t && (s->val == t->val) && isSameTree(s->left, t->left) && isSameTree(s->right, t->right) ? true : false;
}
void recurse(TreeNode *s, TreeNode *t, bool &find) {//遞迴判斷每個s點做為根的樹於t樹相同
if (find || !s)
return;
if (s->val == t->val)
find = isSameTree(s, t);
recurse(s->left, t, find);
recurse(s->right, t, find);
}
bool isSubtree(TreeNode *s, TreeNode *t) {//主函式,為了減枝設定find
if (!t)
return true;

    bool find = false;
    recurse(s, t, find);

    return find;
}

};

[508] 出現次數最多的子樹元素和
class Solution {
public:
map<int, int> sum_; //每一個子樹的值,該值出現的次數
int recurse(TreeNode *curr, int &tree_sum) {
if (!curr)
return 0;

    int left_sum = recurse(curr->left, tree_sum);   //左子樹和
    int right_sum = recurse(curr->right, tree_sum); //右子樹和
    int now_sum = curr->val + left_sum + right_sum; //以當前節點為根的樹和
    sum_[now_sum]++;                                //當前和出現次數+1
    tree_sum += curr->val;                          //總樹和+當前節點值
    return now_sum;
}
vector<int> findFrequentTreeSum(TreeNode *root) {
    int tree_sum = 0, max = -1; //樹總和,最大次數
    recurse(root, tree_sum);
    vector<int> ret;
    for (pair p : sum_)
        if (p.second == max)
            ret.push_back(p.first);
        else if (p.second > max) {
            max = p.second;
            ret.clear();
            ret.push_back(p.first);
        }

    return ret;
}

};