1. 程式人生 > 其它 >LeetCode 501——二叉搜尋樹中的眾數

LeetCode 501——二叉搜尋樹中的眾數

技術標籤:LeetCode刷題

一、題目介紹

給定一個有相同值的二叉搜尋樹(BST),找出 BST 中的所有眾數(出現頻率最高的元素)。

假定 BST 有如下定義:

結點左子樹中所含結點的值小於等於當前結點的值
結點右子樹中所含結點的值大於等於當前結點的值
左子樹和右子樹都是二叉搜尋樹

例如:
給定 BST [1,null,2,2],

   1
    \
     2
    /
   2
返回[2].

提示:如果眾數超過1個,不需考慮輸出順序

進階:你可以不使用額外的空間嗎?(假設由遞迴產生的隱式呼叫棧的開銷不被計算在內)

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/find-mode-in-binary-search-tree

著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

二、解題思路

參考官方題解,使用Mirrors中序遍歷的方法。該方法的重點是為當前節點cur建立前驅節點pre,根據中序遍歷的特點(先遍歷左子樹,再遍歷當前節點,左後在遍歷右子樹),需將當前節點的左子樹中最右邊的節點(即中序遍歷最後訪問到的節點)設定為前驅節點,並且令pre->right = cur。這樣當遍歷完當前節點的左子樹時,可以通過pre訪問到cur。具體實現流程如下:

Morris 中序遍歷的一個重要步驟就是尋找當前節點的前驅節點,並且 Morris 中序遍歷尋找下一個點始終是通過轉移到right 指標指向的位置來完成的。

  1. 如果當前節點沒有左子樹,則遍歷這個點,然後跳轉到當前節點的右子樹。
  2. 如果當前節點有左子樹,那麼它的前驅節點一定在左子樹上,我們可以在左子樹上一直向右行走,找到當前點的前驅節點。

(1)如果前驅節點沒有右子樹,就將前驅節點的right 指標指向當前節點。這一步是為了在遍歷完前驅節點後能找到前驅節點的後繼,也就是當前節點。
(2)如果前驅節點的右子樹為當前節點,說明前驅節點已經被遍歷過並被修改了right 指標,這個時候我們重新將前驅的右孩子設定為空,遍歷當前的點,然後跳轉到當前節點的右子樹。

三、解題程式碼

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int count = 0, maxCount = 0, base;
    vector<int> res;
    void update(int val)
    {
        if(val == base)
            count++;
        else
        {
            count = 1; //更新計數
            base = val;//更新記錄的值            
        }
        if(count == maxCount)
        {
            res.push_back(base);
        }
        else if(count > maxCount)
        {
            maxCount = count;
            res = vector<int> {base};
        }
    }

    vector<int> findMode(TreeNode* root) {
        //mirrors中序遍歷
        TreeNode* cur = root;
        TreeNode* pre = NULL;
        while(cur)
        {
            if(!cur->left) //如果當前節點的左子樹為空
            {
                update(cur->val); //遍歷當前節點
                cur = cur->right; //開始訪問當前節點的右子樹
                continue;
            }
            //當前節點左子樹不為空時
            pre = cur->left; //需要在當前節點的左子樹中尋找其前驅節點
            while(pre->right && pre->right != cur) //在當前節點的左子樹的右下邊找其前驅節點
                pre = pre->right;
            if(!pre->right)
            {
                pre->right = cur;
                cur = cur->left;
            }
            else
            {
                pre->right = NULL;
                update(cur->val);
                cur = cur->right;
            }
        }
        return res;
    }
};

四、解題結果