给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有众数(出现频率最高的元素)。
    如果树中有不止一个众数,可以按 任意顺序 返回。

    假定 BST 满足如下定义:

    • 结点左子树中所含节点的值 小于等于 当前节点的值
    • 结点右子树中所含节点的值 大于等于 当前节点的值
    • 左子树和右子树都是二叉搜索树

    示例 1:
    输入:root = [1,null,2,2]
    输出:[2]

    示例 2:
    输入:root = [0]
    输出:[0]

    众数(出现频率最高的元素),那么可以先统计值得出现频率次数

    1. public int[] findMode(TreeNode root) {
    2. Map<Integer, Integer> timesMap = new HashMap<>();
    3. // 遍历二叉树时统计值的出现次数
    4. order(root, timesMap);
    5. }
    6. /**
    7. * 遍历二叉树时统计值的次数
    8. * @param node
    9. */
    10. private void order(TreeNode node, Map<Integer, Integer> timesMap) {
    11. if (node == null) {
    12. return;
    13. }
    14. timesMap.put(node.val, timesMap.getOrDefault(node.val, 0) + 1);
    15. order(node.left);
    16. order(node.right);
    17. }

    遍历次数结果Map,得到次数最大值

    1. public int[] findMode(TreeNode root) {
    2. Map<Integer, Integer> timesMap = new HashMap<>();
    3. // 遍历二叉树时统计值的出现次数
    4. order(root, timesMap);
    5. // 找到次数最大值
    6. int maxTimes = 0;
    7. for (Map.Entry<Integer, Integer> entry : timesMap.entrySet()) {
    8. maxTimes = Math.max(entry.getValue(), maxTimes);
    9. }
    10. }
    11. /**
    12. * 遍历二叉树时统计值的次数
    13. * @param node
    14. */
    15. private void order(TreeNode node, Map<Integer, Integer> timesMap) {
    16. if (node == null) {
    17. return;
    18. }
    19. timesMap.put(node.val, timesMap.getOrDefault(node.val, 0) + 1);
    20. order(node.left);
    21. order(node.right);
    22. }

    再次遍历次数结果Map,找到出现最大次数的值,放入 List

    1. public int[] findMode(TreeNode root) {
    2. Map<Integer, Integer> timesMap = new HashMap<>();
    3. // 遍历二叉树时统计值的出现次数
    4. order(root, timesMap);
    5. // 找到次数最大值
    6. int maxTimes = 0;
    7. for (Map.Entry<Integer, Integer> entry : timesMap.entrySet()) {
    8. maxTimes = Math.max(entry.getValue(), maxTimes);
    9. }
    10. // 找到出现次数最多的值
    11. List<Integer> maxTimesValList = new ArrayList<>();
    12. for (Map.Entry<Integer, Integer> entry : timesMap.entrySet()) {
    13. if (entry.getValue() == maxTimes) {
    14. maxTimesValList.add(entry.getKey());
    15. }
    16. }
    17. }
    18. /**
    19. * 遍历二叉树时统计值的次数
    20. * @param node
    21. */
    22. private void order(TreeNode node, Map<Integer, Integer> timesMap) {
    23. if (node == null) {
    24. return;
    25. }
    26. timesMap.put(node.val, timesMap.getOrDefault(node.val, 0) + 1);
    27. order(node.left);
    28. order(node.right);
    29. }

    最后将 List 转为 array

    1. public int[] findMode(TreeNode root) {
    2. Map<Integer, Integer> timesMap = new HashMap<>();
    3. // 遍历二叉树时统计值的出现次数
    4. order(root, timesMap);
    5. // 找到次数最大值
    6. int maxTimes = 0;
    7. for (Map.Entry<Integer, Integer> entry : timesMap.entrySet()) {
    8. maxTimes = Math.max(entry.getValue(), maxTimes);
    9. }
    10. // 找到出现次数最多的值
    11. List<Integer> maxTimesValList = new ArrayList<>();
    12. for (Map.Entry<Integer, Integer> entry : timesMap.entrySet()) {
    13. if (entry.getValue() == maxTimes) {
    14. maxTimesValList.add(entry.getKey());
    15. }
    16. }
    17. // List 转 array
    18. int[] result = new int[maxTimesValList.size()];
    19. for (int i = 0; i < maxTimesValList.size(); i++) {
    20. result[i] = maxTimesValList.get(i);
    21. }
    22. return result;
    23. }
    24. /**
    25. * 遍历二叉树时统计值的次数
    26. * @param node
    27. */
    28. private void order(TreeNode node, Map<Integer, Integer> timesMap) {
    29. if (node == null) {
    30. return;
    31. }
    32. timesMap.put(node.val, timesMap.getOrDefault(node.val, 0) + 1);
    33. order(node.left);
    34. order(node.right);
    35. }

    优化算法,减少对 Map 的遍历次数:

    1. int maxTimes = 0;
    2. Map<Integer, Integer> timesMap = new HashMap<>();
    3. public int[] findMode(TreeNode root) {
    4. order(root);
    5. // 找到出现次数最多的值
    6. List<Integer> maxTimesValList = new ArrayList<>();
    7. for (Map.Entry<Integer, Integer> entry : timesMap.entrySet()) {
    8. if (entry.getValue() == maxTimes) {
    9. maxTimesValList.add(entry.getKey());
    10. }
    11. }
    12. // List 转 array
    13. int[] result = new int[maxTimesValList.size()];
    14. for (int i = 0; i < maxTimesValList.size(); i++) {
    15. result[i] = maxTimesValList.get(i);
    16. }
    17. return result;
    18. }
    19. /**
    20. * 遍历二叉树时统计值的次数
    21. * @param node
    22. */
    23. private void order(TreeNode node) {
    24. if (node == null) {
    25. return;
    26. }
    27. int times = timesMap.getOrDefault(node.val, 0).intValue() + 1;
    28. maxTimes = Math.max(maxTimes, times);
    29. timesMap.put(node.val, times);
    30. order(node.left);
    31. order(node.right);
    32. }

    上述算法可以找出并返回二叉树(自然也支持二叉搜索树)中的所有众数。

    但是题目中既然提到了二叉搜索树,那么二叉搜索树和普通二叉树有什么区别呢?

    二叉搜索树的特点:

    • 左子树的值都比根节点的值小
    • 右子树的值都比根节点的值大

    正因为二叉搜索树的特点,那么如果中序遍历二叉搜索树,其遍历结果将是一个有序数组!!!

    1. public int[] findMode(TreeNode root) {
    2. List<Integer> valList = new ArrayList<>();
    3. inOrder(root, valList);
    4. }
    5. /**
    6. * 中序遍历二叉搜索树,得到升序的遍历结果
    7. * @param node
    8. */
    9. private void inOrder(TreeNode node, List<Integer> valList) {
    10. if (node == null) {
    11. return;
    12. }
    13. inOrder(node.left, valList);
    14. valList.add(node.val);
    15. inOrder(node.right, valList);
    16. }

    那怎么从一个升序的有序数组中获取到众数集合呢?
    501. 二叉搜索树中的众数 - 图1

    1. List<Integer> maxValList = new ArrayList<>();
    2. int maxCount = 0;
    3. int preVal = -1;
    4. int count = 0;
    5. for (Integer val : valList) {
    6. if (preVal == -1) {
    7. // 初始化为1
    8. count = 1;
    9. } else if (preVal == val) {
    10. // 值相等,次数加1
    11. count++;
    12. } else {
    13. // 值不相等,次数重置为1
    14. count = 1;
    15. }
    16. // 记录当前值用于下一次比较
    17. preVal = val;
    18. if (count == maxCount) {
    19. // 若次数等于最大次数,将当前值放入结果集
    20. maxValList.add(val);
    21. }
    22. if (count > maxCount) {
    23. // 若次数大于最大次数,清空结果集
    24. maxValList.clear();
    25. // 将当前值放入结果集
    26. maxValList.add(val);
    27. // 将当前次数作为新的最大次数
    28. maxCount = count;
    29. }
    30. }

    完整地算法:

    1. public int[] findMode(TreeNode root) {
    2. List<Integer> valList = new ArrayList<>();
    3. inOrder(root, valList);
    4. List<Integer> maxValList = new ArrayList<>();
    5. int maxCount = 0;
    6. int preVal = -1;
    7. int count = 0;
    8. for (Integer val : valList) {
    9. if (preVal == -1) {
    10. // 初始化为1
    11. count = 1;
    12. } else if (preVal == val) {
    13. // 值相等,次数加1
    14. count++;
    15. } else {
    16. // 值不相等,次数重置为1
    17. count = 1;
    18. }
    19. // 记录当前值用于下一次比较
    20. preVal = val;
    21. if (count == maxCount) {
    22. // 若次数等于最大次数,将当前值放入结果集
    23. maxValList.add(val);
    24. }
    25. if (count > maxCount) {
    26. // 若次数大于最大次数,清空结果集
    27. maxValList.clear();
    28. // 将当前值放入结果集
    29. maxValList.add(val);
    30. // 将当前次数作为新的最大次数
    31. maxCount = count;
    32. }
    33. }
    34. // List 转 array
    35. int[] result = new int[maxValList.size()];
    36. for (int i = 0; i < maxValList.size(); i++) {
    37. result[i] = maxValList.get(i);
    38. }
    39. return result;
    40. }
    41. private void inOrder(TreeNode node, List<Integer> valList) {
    42. if (node == null) {
    43. return;
    44. }
    45. inOrder(node.left, valList);
    46. valList.add(node.val);
    47. inOrder(node.right, valList);
    48. }

    优化算法:

    1. public int[] findMode(TreeNode root) {
    2. List<Integer> maxValList = new ArrayList<>();
    3. inOrder(root, maxValList);
    4. // List 转 array
    5. int[] result = new int[maxValList.size()];
    6. for (int i = 0; i < maxValList.size(); i++) {
    7. result[i] = maxValList.get(i);
    8. }
    9. return result;
    10. }
    11. /**
    12. * 中序遍历二叉搜索树,得到升序的遍历结果
    13. * @param node
    14. */
    15. TreeNode pre = null;
    16. int count;
    17. int maxCount = 0;
    18. public void inOrder(TreeNode node, List<Integer> maxValList) {
    19. if (node == null) {
    20. return;
    21. }
    22. inOrder(node.left, maxValList);
    23. if (pre == null) {
    24. // 第一个节点
    25. count = 1;
    26. } else if (node.val == pre.val) {
    27. // 当前节点和上一个节点值相等
    28. count++;
    29. } else {
    30. // 当前节点和上一个节点值不相等
    31. count = 1;
    32. }
    33. // 记录当前值
    34. pre = node;
    35. // 当前值出现次数和最大次数相等
    36. if (count == maxCount) {
    37. // 放入当前值到目标集合
    38. maxValList.add(node.val);
    39. }
    40. if (count > maxCount) {
    41. // 出现新的最大次数
    42. // 清空集合
    43. maxValList.clear();
    44. // 放入当前值到目标集合
    45. maxValList.add(node.val);
    46. // 重置最大次数
    47. maxCount = count;
    48. }
    49. inOrder(node.right, maxValList);
    50. }