1. 程式人生 > 其它 >206. 反轉連結串列(C++)

206. 反轉連結串列(C++)

目錄

題目

給定一個有相同值的二叉搜尋樹(BST),找出 BST 中的所有眾數。

(出現頻率最高的元素)

假定 BST 有如下定義:

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

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

   1
    \
     2
    /
   2

返回[2].

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

題解

常規遍歷

無視二叉搜尋樹的性質,直接對二叉樹進行遍歷。

同時使用雜湊表對不同數值的頻次進行統計。

將雜湊表排序後再遍歷map找出頻次最高的一組或多組數值

/**
 * Definition for a binary tree node.
 * 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 {
// 編寫兩個私有的函式用於遍歷BST
private:
    void searchBST(TreeNode* cur, unordered_map<int, int> &map) {
        // 設定終止條件
        if (cur == nullptr) return;
        map[cur->val]++;
        searchBST(cur->left, map);
        searchBST(cur->right, map);
    }
    // 自定義sort比較函式
    // static修飾表示該檔案只能在本檔案中呼叫
    bool static cmp(pair<int, int> a, pair<int, int> b) {
        return a.second > b.second;
    }
public:
    vector<int> findMode(TreeNode* root) {
        vector<int> res;
        unordered_map<int, int> map;
        // 先考慮特殊情況
        if (root == nullptr) return res;
        searchBST(root, map);
        vector<pair<int, int>> vec(map.begin(), map.end());
        // 先使用自定義比較規則進行排序
        sort(vec.begin(), vec.end(), cmp);
        res.push_back(vec[0].first);
        // 還要考慮頻率相同的並列元素
        for (int i = 1; i < vec.size(); i++) {
            if (vec[i].second == vec[0].second)
                res.push_back(vec[i].first);
            else break;
        }
        return res;
    }
};

BST性質

二叉搜尋樹(Binary Search Tree)的主要性質在於:

  • 結點左子樹中所含結點的值小於等於當前結點的值
  • 結點右子樹中所含結點的值大於等於當前結點的值

所以如果對二叉樹進行中序遍歷的話,所得的數列表必定是單調遞增的,相等的數值必定鄰近

// 先設定遞迴終止條件
        if (cur == nullptr) return;
        // 中序遍歷
        searchBST(cur->left);
        // 處理當前節點
        if (pre == nullptr) {
            // 說明當前是根節點
            count = 1;
        } else if (pre->val == cur->val) {
            // 臨近節點值相同,原子遞增
            count++;
        } else {
            // 臨界節點值不同,重新進行計數
            count = 1;
        }
        pre = cur;

因此我們在遍歷二叉樹時,設定一個pre來定位當前結點的前一個結點。因為臨近值的結點必定是相鄰的,無非有以下三種情況:

  • 根節點:遍歷首位結點時,pre為空,此時初始化頻次:

    count = 1;

  • pre->val == cur->val:此時對於當前值的計數源自遞增:

    count++;

  • pre->val != cur->val:此時當前值已經更新,需要重置count計數

    count = 1;

每次更新count計數後,我們需要將其與maxCount進行比較:

if (count == maxCount) {
            res.push_back(cur->val);
        }

        if (count > maxCount) {
            // 重新整理maxCount
            maxCount = count;
            // 之前的所有結果都會被刪除
            // 包括破紀錄的數值本身也會先清除後再插入(我殺我自己)
            res.clear();
            res.push_back(cur->val);
        }
  • 如果數值與maxCount相等,則可能是頻率並列第一的數值,便臨時將其新增進結果集中。

  • 如果數值與maxCount不相等,那說明之前的maxCount並不是真正的最高頻次,需要清空已有的結果集。再將目前最高頻詞對應的數值填寫進結果集中。

    因為當前結果集也經歷過count == maxCount的階段,所以會出現當前val被一併清空又重新填入的清空,我刪我自己:)。

完整程式碼如下:

/**
 * Definition for a binary tree node.
 * 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 {
private:
    int count;
    int maxCount;
    vector<int> res;
    TreeNode* pre;
    // pre用於記錄前一個結點,用於數值比較和計數
    void searchBST(TreeNode* cur) {
        // 先設定遞迴終止條件
        if (cur == nullptr) return;
        // 中序遍歷
        searchBST(cur->left);
        // 處理當前節點
        if (pre == nullptr) {
            // 說明當前是根節點
            count = 1;
        } else if (pre->val == cur->val) {
            // 臨近節點值相同,原子遞增
            count++;
        } else {
            // 臨界節點值不同,重新進行計數
            count = 1;
        }
        pre = cur;
        // 計數後與maxcount進行比較
        if (count == maxCount) {
            res.push_back(cur->val);
        }

        if (count > maxCount) {
            // 重新整理maxCount
            maxCount = count;
            // 之前的所有結果都會被刪除
            // 包括破紀錄的數值本身也會先清除後再插入(我殺我自己)
            res.clear();
            res.push_back(cur->val);
        }
        searchBST(cur->right);
        
    }
public:
    vector<int> findMode(TreeNode* root) {
        if (root == nullptr) return res;
        searchBST(root);
        return res;
    }
};