QUESTION
easy
题目描述
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
- 结点左子树中所含结点的值小于等于当前结点的值
- 结点右子树中所含结点的值大于等于当前结点的值
- 左子树和右子树都是二叉搜索树
例如:
给定 BST [1,null,2,2],
1
\
2
/
2
返回[2].
说明
提示:如果众数超过1个,不需考虑输出顺序
进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)
SOLUTION
这道题使用 hash 表存储是很好解决的,但题目中给出了进阶要求——不使用额外的空间
方法一
hash
记录每个节点值出现的次数,max
用来记录出现次数最大的值(方便后续操作),然后遍历就可以了。这个方法几乎适用于任何树,但从中也可以发现并没有使用 BST
的性质。
class Solution {
public:
vector<int> findMode(TreeNode* root) {
unordered_map<int, int> m;
vector<int> res;
int max = 0;
preorder(root, m, max);
for(auto e : m) if(e.second == max) res.push_back(e.first);
return res;
}
void preorder(TreeNode* node, unordered_map<int, int> &m, int &max){
if(node == nullptr) return;
m[node->val]++;
if(max < m[node->val]) max = m[node->val];
preorder(node->left, m, max);
preorder(node->right, m, max);
}
};
方法二
提醒一下:此题的给出的 BST 的定义和以往稍微有点不一样。
count
往下递归计算与参数val
相同的值的节点次数inorder
虽然这里是中序遍历,但其实没用上 BST 中序遍历的性质。用一个max
记录最大次数,调用 count 计算该节点值在该子树中出现的次数。然后与 max 对比,若相等则res
记上该节点的值;若比 max 大,更新 max 的值,清空 res 再记录下节点的值。
这个方法重复遍历了很多很多节点,但也满足进阶的要求,令我意外的是,耗时比方法一还要短(可能是因为没有很大的用例)。
class Solution {
public:
vector<int> findMode(TreeNode* root) {
vector<int> res;
int max = 0;
inorder(root, res, max);
return res;
}
void inorder(TreeNode* node, vector<int> &res, int &max){
if(node == nullptr) return;
inorder(node->left, res, max);
int cnt = count(node, node->val);
if(cnt == max) res.push_back(node->val);
else if(cnt > max){
max = cnt;
res.clear();
res.push_back(node->val);
}
inorder(node->right, res, max);
}
int count(TreeNode* node, int val){
if(node == nullptr) return 0;
return (val == node->val) + count(node->left, val) + count(node->right, val);
}
};
方法三
题目中的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 = nullptr;
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);
}
};