算法与数据结构-树-简单-二叉搜索树中的众数
二叉搜索树中的众数
题目
leetcode原题:501. 二叉搜索树中的众数
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
- 结点左子树中所含结点的值小于等于当前结点的值
- 结点右子树中所含结点的值大于等于当前结点的值
- 左子树和右子树都是二叉搜索树
提示:如果众数超过1个,不需考虑输出顺序
进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)
分析
树的题目要求众数,那么求众数的基础就是遍历树+保存中间值,最后返回众数,乍一看蛮简单。但进阶中的需求提到,尽量不使用额外的空间,意思是不使用map能不能做到?
一般来说,解题分为两种思路:
- 蛮力遍历,保存中间值,通过保存下来的中间值计算输出需要的结果。
- 通过某种方式使得数据有序,在有序的基础上去思考如何不使用额外空间,仅使用O(1)的空间复杂度来解决问题。
首先思考如何有序遍历。
题目有一个特殊的条件,这个树为二叉搜索树,二叉搜索树本身是一定程度有序的,左子树一定小于等于根节点,右子树一定大于等于根节点,那么如何通过遍历让节点有序输出呢?考虑树的三种遍历方式,中序遍历可以实现这个需求!
然后思考如何使用O(1)的空间复杂度来求得众数。
思考到这里,题目就转变为了如果给你一个有序数组,如何使用O(1)空间复杂度求得众数。
考虑一个具体问题:[-1,0,1,1,2,3]
遍历到-1时,众数结果数组为[-1],maxCount=1,依次类推,遍历到第一个1之后,众数数组为[-1,0,1],maxCount依旧为1,接着遍历第二个1,这时发现1的个数为2,大于maxCount,所以需要清空数组,重新把1放进去,并更新maxCount为2,下面的2和3都因为个数小于maxCount不会被加入众数数组中,至此遍历结束。
分析上面的思路,我们需要三个int变量,一个记录了上次遍历数据,一个记录了上次数据的连续个数,另外一个记录了maxCount。
这样大框架就出来了!
总结一下这部分:
- 中序遍历使得从小到大有序
- 利用三个int变量记录中间结果,达到O(1)的时间复杂度
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private List<Integer> resultList = new ArrayList<>();
private int lastNumber;
private int lastCount;
private int maxCount;
public int[] findMode(TreeNode root) {
middleTree(root);
int[] result = new int[resultList.size()];
for(int i = 0;i<=resultList.size()-1;i++){
result[i] = resultList.get(i);
}
return result;
}
private void middleTree(TreeNode root){
if(root == null){
return;
}
middleTree(root.left);
updateList(root.val);
middleTree(root.right);
}
private void updateList(int val){
if(resultList.size() == 0){
lastNumber = val;
lastCount = 1;
maxCount = 1;
resultList.add(val);
}else{
if(val == lastNumber){
lastCount++;
}else{
lastNumber = val;
lastCount = 1;
}
if(lastCount > maxCount){
//清空原来list
resultList.clear();
//加入
resultList.add(val);
//更新maxCount 为 lastCount
maxCount = lastCount;
}else if(lastCount == maxCount){
//加入
resultList.add(val);
}else{
//不加入
}
}
}
}