代码随想录二刷 |二叉树 | 二叉搜索树中的众数
- 题目描述
- 解题思路
- 递归法
- 非二叉搜索树的方式
- 二叉搜索树的方式
- 迭代法
题目描述
501.二叉搜索树中的众数
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
- 结点左子树中所含结点的值小于等于当前结点的值
- 结点右子树中所含结点的值大于等于当前结点的值
- 左子树和右子树都是二叉搜索树
例如:
给定 BST [1,null,2,2],
返回[2]。
提示:如果众数超过1个,不需考虑输出顺序
进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)
解题思路
递归法
非二叉搜索树的方式
最直观的方法是遍历这个树,用map统计频率,把频率排个序,最后取前面高频的元素的集合。
- 遍历二叉树,用map统计频率
// map<int, int> key->元素, value->出现频率
void searchBST(TreeNode* cur, unordered_map<int, int>& map) {if (cur == NULL) return ;map[cur->val]++; // 统计元素频率searchBST(cur->left, map);searchBST(cur->right, map);return;
}
- 把统计出来的出现频率排序
将map转化为数组再进行排序(C++中如果使用std::map或者std::multimap可以对key排序,但不能对value排序。),vector里面放的也是pair<int, int>类型的数据,第一个int为元素,第二个int为出现频率。
bool static cmp (const pair<int, int>& a, const pair<int, int>& b) {return a.second > b.second; // 按照频率从大到小排序
}
vector<pair<int, int>> vec(map.begin(), map.end());
sort(vec.begin(), vec.end(), cmp); // 给频率排序
- 取高频元素
此时数组vector中已经是存放着按照频率排好序的pair,那么把前面高频的元素取出来就可以了。
result.push_back(vec[0].first);
for (int i = 1; i < vec.size(); i++) {if (vec[i].second == vec[0].second) result.push_back(vec[i].first);else break;
}
return result;
整体代码:
class Solution {
private:void searchBST(TreeNode* cur, unordered_map<int, int>& map) {if (cur == NULL) return;map[cur->val]++;searchBST(cur->left, map);searchBST(cur->right, map);return;}bool static cmp (const pair<int, int>& a, const pair<int, int>& b) {return a.second > b.second;}
public: vector<int> findMode(TreeNode* root) {unordered_map<int, int> map;vector<int> result;if (root == NULL) return result;searchBST(root, map);vector<pair<int, int>> vec(map.begin(), map.end());sort(vec.begin(), vec.end(), cmp);result.push_back(vec[0].first);for (int i = 1; i < vec.size(); i++) {if (vec[i].second == vec[0].second)result.push_back(vec[i].first);else break;}return result;}
};
二叉搜索树的方式
二叉搜索树的中序遍历是有序的。
在遍历有序数组的元素出现频率时,一般采用从头遍历的方式,让相邻的两个元素作比较,把出现频率最高的元素输出。
在树上也可以这样做,我们设置一个指针指向前一个节点,这样每次cur(当前节点)才能和pre(前一个节点)作比较。
而且初始化的时候pre = NULL,这样当pre为NULL时候,我们就知道这是比较的第一个元素。
代码如下:
if (pre == NULL) { // 第一个节点count = 1; // 频率为1
} else if (pre->val == cur->val) { // 与前一个节点数值相同count++;
} else { // 与前一个节点数值不同count = 1;
}
pre = cur; // 更新上一个节点
本题要求的是最大频率的元素集合,在数组上,要先找出最大频率,然后再遍历一次数组,将最大频率的元素放入集合中。这样就遍历了两次数组。
本题也可以遍历两次数组,但这里提供一种只遍历一次的写法。
如果频率 = 最大频率 (count = maxCount),就将这个元素加入到结果集中:
if (count == maxCount) {result.push_back(cur->val);
}
这里存在一个问题,如果此时的maxCount不是最大频率就会出现错误,因此要做如下操作:
当频率大于最大频率(count > maxCount)时,不仅要更新 maxCount,而且要清空结果集result,因为当前结果集中的元素已经不是最大频率了。
if (count > maxCount) { // 如果计数大于最大值maxCount = count; // 更新最大频率result.clear(); // 晴空resultresult.push_back(cur=>val);
}
完整代码如下:
class Solution {
private:int maxCount = 0;int count = 0;TreeNode* pre = NULL;vector<int> result;void searchBST(TreeNode* cur) {if (cur == NULL) return;searchBST(cur->left);if (pre == NULL) {count = 1;} else if(pre->val == cur->val) {count++;} else {count = 1;}pre = cur;if (count == maxCount) {result.push_back(cur->val);}if (count > maxCount) {maxCount = count;result.clear();result.push_back(cur->val);}searchBST(cur->right);return;}public:vector<int> findMode(TreeNode* root) {count = 0;maxCount = 0;pre = NULL;result.claer();searchBST(root);return result;}
};
迭代法
只要把中序遍历转成迭代,中间节点的处理逻辑完全一样。
class Solution {
public:vector<int> findMode(TreeNode* root) {stack<TreeNode*> st;TreeNode* cur = root;TreeNode* pre = NULL:int maxCount = 0;int count = 0;vector<int> result;while (cur != NULL || !st.empty()) {if (cur != NULL) {st.push(cur);cur = cur->left;} else {cur = st.top();st.pop();if (pre = NULL) {count = 1;} else if (pre->val = cur->val) {count++;} else {count = 1;}if (count = maxCount) {result.push_back(cur->val);}if (count > maxCount) {maxCount = count;result.clear();result.push_back(cur->val);}pre = cur;cur = cur->right;}}return result;}
};