[LeetCode] Find Mode in Binary Search Tree 找二分搜索數的眾數


 

Given a binary search tree (BST) with duplicates, find all the mode(s) (the most frequently occurred element) in the given BST.

Assume a BST is defined as follows:

  • The left subtree of a node contains only nodes with keys less than or equal to the node's key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node's key.
  • Both the left and right subtrees must also be binary search trees.

 

For example:
Given BST [1,null,2,2],

   1
    \
     2
    /
   2

 

return [2].

Note: If a tree has more than one mode, you can return them in any order.

Follow up: Could you do that without using any extra space? (Assume that the implicit stack space incurred due to recursion does not count).

 

這道題讓我們求二分搜索樹中的眾數,這里定義的二分搜索樹中左根右結點之間的關系是小於等於的,有些題目中是嚴格小於的,所以一定要看清題目要求。所謂的眾數就是出現最多次的數字,可以有多個,那么這道題比較直接點思路就是利用一個哈希表來記錄數字和其出現次數之前的映射,然后維護一個變量mx來記錄當前最多的次數值,這樣在遍歷完樹之后,根據這個mx值就能把對應的元素找出來。那么用這種方法的話就不需要用到二分搜索樹的性質了,隨意一種遍歷方式都可以,下面我們來看遞歸的中序遍歷的解法如下:

 

解法一:

class Solution {
public:
    vector<int> findMode(TreeNode* root) {
        vector<int> res;
        int mx = 0;
        unordered_map<int, int> m; 
        inorder(root, m, mx);
        for (auto a : m) {
            if (a.second == mx) {
                res.push_back(a.first);
            }
        }
        return res;
    }
    void inorder(TreeNode* node, unordered_map<int, int>& m, int& mx) {
        if (!node) return;
        inorder(node->left, m, mx);
        mx = max(mx, ++m[node->val]);
        inorder(node->right, m, mx);
    }
};

 

下面這種解法是上面方法的迭代形式,也是用的中序遍歷的方法,有興趣的童鞋可以實現其他的遍歷方法:

 

解法二:

class Solution {
public:
    vector<int> findMode(TreeNode* root) {
        if (!root) return {};
        vector<int> res;
        TreeNode *p = root;
        stack<TreeNode*> s;
        unordered_map<int, int> m;
        int mx = 0;
        while (!s.empty() || p) {
            while (p) {
                s.push(p);
                p = p->left;
            }
            p = s.top(); s.pop();
            mx = max(mx, ++m[p->val]);
            p = p->right;
        }
        for (auto a : m) {
            if (a.second == mx) {
                res.push_back(a.first);
            }
        }
        return res;
    }
};

 

題目中的follow up說了讓我們不用除了遞歸中的隱含棧之外的額外空間,那么我們就不能用哈希表了,不過這也不難,由於是二分搜索樹,那么我們中序遍歷出來的結果就是有序的,這樣我們只要比較前后兩個元素是否相等,就等統計出現某個元素出現的次數,因為相同的元素肯定是都在一起的。我們需要一個結點變量pre來記錄上一個遍歷到的結點,然后mx還是記錄最大的次數,cnt來計數當前元素出現的個數,我們在中序遍歷的時候,如果pre不為空,說明當前不是第一個結點,我們和之前一個結點值比較,如果相等,cnt自增1,如果不等,cnt重置1。如果此時cnt大於了mx,那么我們清空結果res,並把當前結點值加入結果res,如果cnt等於mx,那我們直接將當前結點值加入結果res,然后mx賦值為cnt。最后我們要把pre更新為當前結點,參見代碼如下:

 

解法三:

class Solution {
public:
    vector<int> findMode(TreeNode* root) {
        vector<int> res;
        int mx = 0, cnt = 1;
        TreeNode *pre = NULL;
        inorder(root, pre, cnt, mx, res);
        return res;
    }
    void inorder(TreeNode* node, TreeNode*& pre, int& cnt, int& mx, vector<int>& res) {
        if (!node) return;
        inorder(node->left, pre, cnt, mx, res);
        if (pre) {
            cnt = (node->val == pre->val) ? cnt + 1 : 1;
        }
        if (cnt >= mx) {
            if (cnt > mx) res.clear();
            res.push_back(node->val);
            mx = cnt;
        } 
        pre = node;
        inorder(node->right, pre, cnt, mx, res);
    }
};

 

下面這種方法是上面解法的迭代寫法,思路基本相同,可以參考上面的講解,參見代碼如下:

 

解法四:

class Solution {
public:
    vector<int> findMode(TreeNode* root) {
        if (!root) return {};
        vector<int> res;
        TreeNode *p = root, *pre = NULL;
        stack<TreeNode*> s;
        int mx = 0, cnt = 1;;
        while (!s.empty() || p) {
            while (p) {
                s.push(p);
                p = p->left;
            }
            p = s.top(); s.pop();
            if (pre) {
                cnt = (p->val == pre->val) ? cnt + 1 : 1;
            }
            if (cnt >= mx) {
                if (cnt > mx) res.clear();
                res.push_back(p->val);
                mx = cnt;
            }
            pre = p;
            p = p->right;
        }
        return res;
    }
};

 

類似題目:

Binary Tree Inorder Traversal

 

參考資料:

https://discuss.leetcode.com/topic/77335/proper-o-1-space

https://discuss.leetcode.com/topic/77080/c-dfs-time-o-n-space-o-n

https://discuss.leetcode.com/topic/77077/ugly-but-straight-forward-java-solution

https://discuss.leetcode.com/topic/77330/java-4ms-beats-100-extra-o-1-solution-no-map

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM