1 题目
https://leetcode.cn/problems/find-mode-in-binary-search-tree/description/
给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。如果树中有不止一个众数,可以按任意顺序
返回。
假定 BST 满足如下定义:
- 结点左子树中所含节点的值 小于等于 当前节点的值
- 结点右子树中所含节点的值 大于等于 当前节点的值
- 左子树和右子树都是二叉搜索树
2 思路
2.1 一般二叉树求众数
从一般的角度考虑,求解二叉树的众数;遍历二叉树,获取所有的值,求解众数。
如何记录频率?
可以使用Map,然后对Map进行排序,求出现次数最大的树。时间复杂度为O(nlogn),空间复杂度为O(n)。也可以不排序,直接求频率最大的数。时间复杂度为O(n), 空间复杂度为O(n)
对Map进行排序,求频次最高的树,即为众数:
class Solution {
public int[] findMode1(TreeNode root) {
if (root == null) return new int[0];
// 遍历统计个数
Map<Integer, Integer> map = new HashMap<>();
inorderTree(root, map);
// 对空hashMap进行排序
List<Map.Entry<Integer, Integer>> mapList = map.entrySet().stream().sorted((c1, c2) -> {
return c2.getValue() - c1.getValue(); // 大的减小的
}).collect(Collectors.toList());
List<Integer> nums = new LinkedList<>();
nums.add(mapList.get(0).getKey()); // 存放Key
for (int i = 1; i < mapList.size(); i++) {
if (mapList.get(i).getValue().equals(mapList.get(0).getValue())) { // 比较value
nums.add(mapList.get(i).getKey());
} else {
break; // 后面的不是
}
}
return nums.stream().mapToInt(Integer::intValue).toArray();
}
public void inorderTree(TreeNode root, Map<Integer, Integer> map) {
if (root != null) {
inorderTree(root.left, map);
map.put(root.val, map.getOrDefault(root.val, 0) + 1);
inorderTree(root.right, map);
}
}
}
Note: 易出错的点
- map.entrySet() 通过stream的方式转化微List
- stream.sort()中,大在前则
大-小
,否则小-大
- 明确什么Key和value的关系,尤其是在Map中采用相同类型的时候
不排序直接遍历Map求解众数
- 使用计数器计算频次
- 使用列表保存众数
- 【注意】当有新的众数发现的时候,排空列表
class Solution {
public int[] findMode(TreeNode root) {
Map<Integer, Integer> map = new HashMap<>();
inorderTree(root, map);
int maxCount = 0;
List<Integer> nums = new LinkedList<>();
for (Map.Entry<Integer, Integer> entry: map.entrySet()) {
if (maxCount < entry.getValue()) {
maxCount = entry.getValue();
nums.clear();
nums.add(entry.getKey());
}
// } else {
// maxCount > entry.getValue() 也会加进来
// nums.add(entry.getKey());
// }
else if (maxCount == entry.getValue()) { // 记得添加else,否则会计算两次
nums.add(entry.getKey());
}
}
return nums.stream().mapToInt(Integer::intValue).toArray();
}
public void inorderTree(TreeNode root, Map<Integer, Integer> map) {
if (root != null) {
inorderTree(root.left, map);
map.put(root.val, map.getOrDefault(root.val, 0) + 1);
inorderTree(root.right, map);
}
}
}
2.2 优化:BST树的解法:中序获取有序数组后提取众数
直接从BST中序获取有序的序列,使用有序序列求解众数
- 和前一个元素比较,记录count大小,相等则加1,否则赋值为1
- 获取count后,使用count和最大的count相比较,想等则为重复元素;否则更新众数
class Solution {
public int[] findMode(TreeNode root) {
if (root == null) return new int[0];
List<Integer> numList = new LinkedList<>();
inorderTree(root, numList);
// 众数计数器
List<Integer> nums = new LinkedList<>();
// 记录第一个数
int count = 1;
int maxCount = 1;
int num = numList.get(0);
nums.add(num);
// 对nums进行遍历求众数
for (int i = 1; i < numList.size(); i++) {
if (Objects.equals(numList.get(i - 1), numList.get(i))) {
count++;
} else {
count = 1;
}
// 集中对count进行判断
num = numList.get(i);
if (count == maxCount) {
nums.add(num);
}
if (count > maxCount) {
maxCount = count;
nums.clear();
nums.add(num);
}
}
return nums.stream().mapToInt(Integer::intValue).toArray();
}
public void inorderTree(TreeNode root, List<Integer> nums) {
if (root != null) {
inorderTree(root.left, nums);
nums.add(root.val);
inorderTree(root.right, nums);
}
}
}
2.3 在二叉树的遍历中实现 使用prev指针
基本与有序数组的遍历是一样的
- 注意:使用prev 在prev赋值之后
- 递归时,保存prev
class Solution4 {
public int[] findMode(TreeNode root) {
List<Integer> nums = new LinkedList<>();
inorderTree(root, nums);
return nums.stream().mapToInt(Integer::intValue).toArray();
}
private TreeNode prev = null;
private int count = 1;
private int maxCount = 1;
public void inorderTree(TreeNode root, List<Integer> nums) {
if (root != null) {
inorderTree(root.left, nums);
if (prev != null) {
if (prev.val == root.val) {
count++;
} else {
count = 1;
}
}
if (count == maxCount) {
nums.add(root.val);
}
if (count > maxCount) {
maxCount = count;
nums.clear();
nums.add(root.val);
}
// 保存当前的值,供下一次使用
prev = root;
inorderTree(root.right, nums);
}
}
}
ACM输入输出
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) {this.val = val; }
}
// Solution
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// Solution
while (in.hasNext()) {
String[] strNums = in.nextLine().split(" ");
List<TreeNode> nodes = new LinkedList<>();
for (String strNum: strNums) {
if (!strNum.isEmpty()) {
if (strNum.equals("null")) {
nodes.add(null);
} else {
nodes.add(new TreeNode(Integer.parseInt(strNum)));
}
}
}
TreeNode root = constructTree(nodes);
int[] nums = solution.findMode(root);
for (int n: nums) {
System.out.print(n + " ");
}
System.out.println();
}
}
public static TreeNode constructTree(List<TreeNode> nodes) {
if (!nodes.isEmpty()) {
TreeNode node = nodes.remove(0);
if (node != null) {
node.left = constructTree(nodes);
node.right = constructTree(nodes);
}
return node;
}
return null;
}
}
/*
test case:
1 null 2 2
r = [2]
1 1 1 null null 2 2
0
r = [0]
2 3 4 5 6
r = [2, 3, 4, 5, 6]
*/