【力扣日记】501 二叉搜索树中的众数 | 根据字典值排序

题目描述

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

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

进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)

算法思路

NAIVE

第一步,用字典来计数

class Solution:
    def findMode(self, root: TreeNode):
        if not root:return []
        di=collections.defaultdict(int)
        def bfs(root,di={}):
            if not root:return []
            di[root.val]+=1
            bfs(root.left,di)
            bfs(root.right,di)
        bfs(root,di)

第二步,给字典按值排序,将众数放入列表

        d1=sorted(di.items(), key=lambda x: x[1])
        l,MAX=d1.pop()
        ls=[]
        ls.append(l)

第三步,根据最大值判断是否还有其他众数。

        while d1:
            if d1[-1][1]==MAX:
                ls.append(d1.pop()[0])
            else:break
        return ls

执行用时 :60 ms, 在所有 Python3 提交中击败了80.28%的用户

值得一提的是这种方法适合求所有树的众数。

IMPROVE

基于搜索树的中序遍历是递增数组,由此思想可得仅使用O(1)空间的方法。

class Solution:
    def findMode(self, root: TreeNode):
        if not root:return []
        res=[]
        pro=None
        curtime,maxtime=1,0
        def inorder(root):
            nonlocal pro
            nonlocal curtime
            nonlocal maxtime
            if not root:return
            inorder(root.left)
            if pro:
                if root.val == pro.val:curtime+=1
                else:curtime=1
            pro = root
            if curtime==maxtime:res.append(root.val)
            elif curtime>maxtime:
                res.clear()
                res.append(root.val)
                maxtime=curtime

            inorder(root.right)
        inorder(root)
        return res

!res是序列,可以直接修改。

!必须要提的是本来是把前一个节点pro放在定义的inorder函数里的,但是对于测例[1,None,2,2],永远在从第三层的2跳回到第二层的2那里时,pro变成了指向根节点1. 所以输出值总是[1,2,2]

一直不知道原因!气死。我还是没完全掌握递归的内在。
解决方法:将储存前置值的pro变量变成内嵌函数外的外部函数的变量,通过nonlocal声明来修改。

补充一下,后来发现curtime,maxtime也跳反,一气之下都声明成外部变量。

!关于如上问题,结合递归的定义,可能是内嵌函数的所有变量都在递归调用时将当时的状态push进栈里,即使在下一层做了修改,当栈返回时都恢复了当初的状态。

            if pro:
                if root.val == pro.val:curtime+=1
                else:curtime=1

可以替换为

            if pro:curtime=curtime+1 if root.val == pro.val else 1

执行用时 :52 ms, 在所有 Python3 提交中击败了97.21%的用户

你可能感兴趣的:(力扣日记)