LeetCode 501. Find Mode in Binary Search Tree

20 篇文章 0 订阅

LeetCode 501. Find Mode in Binary Search Tree

题目描述

给定具有重复项的二叉搜索树 (BST) 的根,返回其中的所有模式(即最常出现的元素)。

假设 BST 有如下定义:

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

示例


例如:
给定 BST [1,null,2,2],

   1
    \
     2
    /
   2

返回[2].

提示:如果众数超过1个,不需考虑输出顺序

解题思路

方法一:中序遍历

二叉搜索树的中序遍历是一个非递减的序列,因此我们可以对二叉搜索树进行一次中序遍历,就可以得到有序的结果。

在中序遍历的过程中,我们需要记录当前的数以及当前的数的出现次数,对于二叉搜索树而言,相同的数一定出现在相邻的位置,因此我们可以在中序遍历的过程中更新当前数的出现次数,从而得到所有数出现的次数。

在中序遍历结束后,我们使用哈希表记录所有数出现的次数中的最大值,然后收集所有出现次数等于该最大值的数,即为所有出现次数最多的数。

方法二:Morris 中序遍历

在方法一中,我们对整棵树进行了一次中序遍历,然后对所有数出现的次数进行了一次遍历,因此总共进行了两次遍历。

我们也可以在中序遍历的过程中直接找出所有出现次数最多的数,这样可以只进行一次遍历。

我们可以用一种叫做 Morris 遍历的方法,来实现中序遍历。这种方法能将原本需要使用栈来解决的问题,转换为对空间复杂度的要求为 O(1) 的问题。

Morris 遍历的核心思想是利用树中大量的空指针,从而省去使用栈来进行中序遍历的过程。我们首先将当前节点current 初始化为根节点,然后对于当前节点current,如果其左子节点不为空,我们将其左子节点的最右侧节点的右子节点指向current,否则我们将其左子节点指向current。对于前者,我们在遍历完左子树之后,通过这个指向走回了current,因此我们可以将这个右子节点的右指针重新指向空。这样做的目的是为了将这个节点重新接回原来的树,并且不影响遍历的过程。而对于后者,我们在遍历完当前节点之后,通过这个指向走回了current,因此我们可以将左子节点指向current。这样做的目的是为了在遍历完当前节点之后,能够遍历其右子树。

在 Morris 遍历中,每个节点会被访问两次,因此总时间复杂度为 O(2n)=O(n)。

代码

Java

class Solution {
    public int[] findMode(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        int[] res = new int[0];
        if (root == null) {
            return res;
        }
        TreeNode cur = root;
        TreeNode pre = null;
        int curCount = 1;
        int maxCount = 1;
        while (cur != null) {
            if (cur.left == null) {
                if (pre != null && pre.val == cur.val) {
                    curCount++;
                } else {
                    curCount = 1;
                }
                if (curCount == maxCount) {
                    list.add(cur.val);
                } else if (curCount > maxCount) {
                    maxCount = curCount;
                    list.clear();
                    list.add(cur.val);
                }
                pre = cur;
                cur = cur.right;
            } else {
                TreeNode node = cur.left;
                while (node.right != null && node.right != cur) {
                    node = node.right;
                }
                if (node.right == null) {
                    node.right = cur;
                    cur = cur.left;
                } else {
                    if (pre != null && pre.val == cur.val) {
                        curCount++;
                    } else {
                        curCount = 1;
                    }
                    if (curCount == maxCount) {
                        list.add(cur.val);
                    } else if (curCount > maxCount) {
                        maxCount = curCount;
                        list.clear();
                        list.add(cur.val);
                    }
                    pre = cur;
                    node.right = null;
                    cur = cur.right;
                }
            }
        }
        res = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            res[i] = list.get(i);
        }
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值