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 = ;
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 = ;
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 = , cnt = ;
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 + : ;
}
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 = , cnt = ;;
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 + : ;
}
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 题目讲解汇总(持续更新中...)

最新文章

  1. Scrum vs. PMP vs. PRINCE2的发展趋势图
  2. Unicode 互转
  3. Object Graph Serialization
  4. Linux基础精华
  5. Python-S13-day2-之购物车
  6. rm 注意
  7. python学习笔记22(group)
  8. linux中cat more less head tail 命令区别
  9. BZOJ_1036_[ZJOI2008]_树的统计Conut_(树链剖分)
  10. Performance tuning library cache lock &amp; single-task message
  11. Socket服务端口长连接最多能支持多少?
  12. Android开发之漫漫长途 Ⅷ——Android Binder(也许是最容易理解的)
  13. Webpack 2 视频教程 006 - 使用快捷方式进行编译
  14. OpenCV——PS 图层混合算法 (四)
  15. Codeforces Round #421 (Div. 2)
  16. Linux之备份(tar)/解压与压缩(gzip,bzip2,xz)【待完善】
  17. 如何用Win7远程链接ubuntu14.04桌面
  18. Java开发者应该列入年度计划的5件事
  19. knockoutjs -- all built-in buildings
  20. Java中获取运行代码的类名、方法名

热门文章

  1. windows环境下,apache虚拟主机配置
  2. Alpha冲刺No.9
  3. 2017-2018-1 Java演绎法 第三周 作业
  4. 冲刺NO.9
  5. Linux安装mongodb总结
  6. CNN中的padding
  7. animation &amp; @keyframes 实现loading效果
  8. 申请JetBrains学生免费注册码
  9. dede观看总结自己总结
  10. Java排序算法之快速排序