24.二叉搜索树中的众数

题目描述

给定一个有相同值的二叉搜索树(BST),找出BST中的所有众数(出现频率最高的元素)。

BST定义如下:

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

解题思路

中序遍历

首先明确一个概念,一棵BST的中序遍历序列是一个非递减的有序序列。而且重复出现的数字一定是连续出现的。所以,我们可以顺序扫描中序遍历序列,用 base记录当前的数字,用count记录当前数字重复的次数,用maxCount来维护已经扫描过的数当中出现最多的那个数字的出现次数,用answer数组记录出现的众数。每次扫描到一个新的元素:

  • 首先更新base和count:
    • 如果该元素和base相等,那么count自增1
    • 否则将base更新为当前数字,count复位为1
  • 然后更新maxCount:
    • 如果count = maxCount,那么说明当前的这个数字(base)出现的次数等于当前众数出现的次数,将base加入answer数组
    • 如果count > maxCount,那么说明当前的这个数字(base)出现的次数大于当前众数出现的次数,因此,将maxCount更新为count,清空answer数组后将base加入answer数组

将上述操作封装成一个函数,剩下的就是解决中序遍历的问题。

普通的中序遍历,空间复杂度为O(n),而Morris中序遍历可以把空间复杂度优化到O(1)。

Morris中序遍历可以在遍历完左子树之后回到当前节点。我们希望当前的节点在遍历完当前点的前驱之后被遍历,我们可以考虑修改它的前驱结点的right指针。当前节点的前驱结点的right指针可能本来就指向当前节点(前驱是当前节点的父节点),也可能是当前节点左子树最右下的节点。如果是后者,我们希望遍历完这个前驱结点之后再回到当前节点,可以将它的right指针指向当前节点。

Morris中序遍历的一个重要步骤就是寻找当前节点的前驱节点,并且Morris中序遍历寻找下一个点始终是通过转移到right指针指向的位置来完成的。

  • 如果当前节点没有左子树,则遍历这个点,然后跳转到当前节点的右子树。
  • 如果当前节点有左子树,那么它的前驱节点一定在左子树上,我们可以在左子树上一直向右走,找到当前点的前驱节点。
    • 如果前驱节点没有右子树,就将前驱结点的right指针指向当前节点。这一步是为了在遍历完前驱节点后能找到前驱节点的后继,也就是当前节点。
    • 如果前驱节点的右子树为当前节点,说明前驱节点已经被遍历过并被修改了right指针,这个时候我们重新将前驱的右孩子设置为空,遍历当前的点,然后跳转到当前节点的右子树。

Code:

class Solution{
    int base,count,maxCount;
    List<Integer> ans = new ArrayList<>();

    public int[] findMode(TreeNode root){
        TreeNode cur = root,pre = null;
        while(cur != null){
            if(cur.left == null){
                update(cur.val);
                cur = cur.right;
                continue;
            }
            pre = cur.left;
            while(pre.right != null && pre.right != cur){
                pre = pre.right;
            }
            if(pre.right == null){
                pre.right = cur;
                cur = cur.left;
            }else{
                pre.right = null;
                update(cur.val);
                cur = cur.right;
            }
        }
        int[] res = new int[ans.size()];
        for(int i = 0;i < ans.size();i++){
            res[i] = ans.get(i);
        }
        return res;
    }
    public void update(int x){
        if(x == base){
            count++;
        }else{
            count = 1;
            base = x;
        }
        if(count == maxCount){
            ans.add(base);
        }
        if(count > maxCount){
            maxCount = count;
            ans.clear();
            ans.add(base);
        }
    }
}

results matching ""

    No results matching ""