206. 反轉連結串列(C++)
阿新 • • 發佈:2021-11-30
目錄
。
題目
給定一個有相同值的二叉搜尋樹(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;
}
};