[LeetCode] Find Mode in Binary Search Tree 找二分搜索数的众数
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值就能把对应的元素找出来。那么用这种方法的话就不需要用到二分搜索树的性质了,随意一种遍历方式都可以,下面我们来看递归的中序遍历的解法如下:
答案可能不止一个,也就是有多个值出现的次数一样多。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int[] findMode(TreeNode root) {
List<Integer> list = new ArrayList<>();
Map<Integer, Integer> map = new HashMap<>();
help(root, list);
int count = 1;
int max = 1;
int index = 0;
int[] arr = new int[list.size()];
for(int i = 1; i < list.size(); i++){
int pre = list.get(i-1);
if(list.get(i) == pre){
count++;
max = Math.max(count, max);
continue;
}
map.put(i-1, count);
count = 1;
}
Integer key = null;
Iterator iter = map.keySet().iterator();
while(iter.hasNext()){
key = (Integer)iter.next();
if(map.get(key) == max){
arr[index++] = key;
}
}
return arr;
}
private void help(TreeNode root, List<Integer> list){
if(root == null)
return;
help(root.left, list);
list.add(root.val);
help(root.right, list);
}
}
解法二:
目中的follow up说了让我们不用除了递归中的隐含栈之外的额外空间,那么我们就不能用哈希表了,不过这也不难,由于是二分搜索树,那么我们中序遍历出来的结果就是有序的,这样我们只要比较前后两个元素是否相等,就等统计出现某个元素出现的次数,因为相同的元素肯定是都在一起的。我们需要一个结点变量pre来记录上一个遍历到的结点,然后mx还是记录最大的次数,cnt来计数当前元素出现的个数,我们在中序遍历的时候,如果pre不为空,说明当前不是第一个结点,我们和之前一个结点值比较,如果相等,cnt自增1,如果不等,cnt重置1。如果此时cnt大于了mx,那么我们清空结果res,并把当前结点值加入结果res,如果cnt等于mx,那我们直接将当前结点值加入结果res,然后mx赋值为cnt。最后我们要把pre更新为当前结点,参见代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private int count = 1;
private int max = 1;
private int val = 0;
private TreeNode preNode = null;
public int[] findMode(TreeNode root) {
List<Integer> maxCntNums = new ArrayList<>();
inOrder(root,maxCntNums);
int[] ret = new int[maxCntNums.size()]; //integer转换为int
int idx = 0;
for (int num : maxCntNums) {
ret[idx++] = num;
}
return ret;
}
private void inOrder(TreeNode root, List<Integer> nums) {
if(root == null) return;
inOrder(root.left, nums);
if(preNode != null)
if(preNode.val == root.val)
count++;
else
count = 1;
if(count > max){ //如果是出现了最大的那个 只保留一个值
max = count;
nums.clear();
nums.add(root.val);
}
else if(count == max){//如果最大的值有多个 都保留
nums.add(root.val);
}
preNode = root;
inOrder(root.right, nums);
}
}