leetcode98/530/501/538.二叉搜索树属性题型总结

其实你看见二叉搜索树,把它和中序遍历联系起来就好了,二叉搜索树结构成立  == 中序遍历有序,这两者之间有等价关系,为什么?

因为l mid r的中序遍历顺序与二叉搜索树 左子树  < 中节点 < 右子树的结构性质吻合,这两者等价性的必要与充分我就不证明了,接下来放题目总结以及代码技巧。

双指针遍历思想:定义一个pre代表前节点,不断更新pre

leetcode98.验证二叉搜索树

中序遍历,当访问到当前节点时,两者对比,如果pre >= node,就返回False,不用遍历完整棵树,一旦发现False就直接层层返回。

其实这和在链表的操作没有本质区别,就是判定一个递增链表。

递归法1:不让空节点进入递归的风格

class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        self.pre = None
        def recursion(node):
            #不让空节点进入递归
            #左
            if node.left:
                result_l = recursion(node.left)
                #只要有不符合条件的,就直接返回False,不用继续遍历整棵树
                if not result_l:
                    return False
            #中
            if self.pre and self.pre.val >= node.val:
                return False
            #更新pre节点,记录前一个节点
            self.pre = node
            #右
            if node.right:
                result_r = recursion(node.right)
                if not result_r:
                    return False
            #如果都符合,向上层函数返回True
            return True
        return recursion(root)

递归法2:允许空节点进入递归的风格
 

class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        self.pre = None
        def inorder_traversal(node):
            #终止条件改为空节点向上层直接返回True
            if not node:
                return True
            result_l = inorder_traversal(node.left)
            if not result_l:
                return False
            if self.pre and self.pre.val >= node.val:
                return False
            self.pre = node
            result_r = inorder_traversal(node.right)
            if not result_r:
                return False
            return True
        return inorder_traversal(root)

迭代法:用栈模拟中序遍历

class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        stk = []
        stk.append((root, False))
        pre = None
        while stk:
            (node, is_visited)  = stk.pop()
            if not is_visited:
                if node.right:
                    stk.append((node.right, False))
                stk.append((node, True))
                if node.left:
                    stk.append((node.left, False))
            else:
                if pre and pre.val >= node.val:
                    return False
                pre = node
        return True

leetcode530.二叉搜索树的最小绝对差

同样采用双指针,记录前一个节点,不断更新差值,直到遍历完整棵树(打擂台的方式找最小值)

递归法:

class Solution:
    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
        self.pre = None
        self.res = float('inf')
        def inorder_traversal(node):
            if node.left:
                inorder_traversal(node.left)
            if self.pre:
                delta = node.val - self.pre.val
                self.res = min(self.res, delta)
            self.pre = node
            if node.right:
                inorder_traversal(node.right)
        inorder_traversal(root)
        return self.res

迭代法:

同样也有迭代法,不重复写了

leetcode.501二叉搜索树种的众数

直观想法,我遍历一遍存到字典里,然后找字典value最大对应的keys就行,不过这就需要额外O(n)的空间,以及需要多遍历一次字典的时间复杂度O(n)。

是否可以一次遍历二叉搜索树就找到答案?
思路如下:1、维护一个max_count(代表目前众数的数量)
                  2、中序遍历二叉搜索树,该顺序遍历是有序的,那对于一个有序数组,我同样用一个pre指针记录前节点,如果pre.val == cur.val,那我计数count+1,如果pre.val != cur.val,那count恢复为1。更新完count之后,count与max_count作比较
                 3、如果count == max_count,在res列表里加入当前节点值
                       如果count > max_count,把res列表清空(众数更新,之前的数作废),再加入
                       当前节点的值

递归法:

class Solution:
    def findMode(self, root: Optional[TreeNode]) -> List[int]:
        self.count = 1
        self.max_count = 1
        self.pre = None
        res = []
        def inorder_traversal(node):
            if not node:
                return
            inorder_traversal(node.left)#left
            #mid
            if self.pre:
                if self.pre.val == node.val:
                    self.count += 1
                else:
                    self.count = 1
                if self.count == self.max_count:
                    res.append(node.val)
                elif self.count > self.max_count:
                    self.max_count = self.count
                    #先clear
                    res.clear()
                    res.append(node.val)
            #第一个节点要加进res
            else:
                res.append(node.val)
            self.pre = node

            inorder_traversal(node.right)#right
        inorder_traversal(root)
        return res

迭代法:

class Solution:
    def findMode(self, root: Optional[TreeNode]) -> List[int]:
        res = []
        stk = []
        pre = None
        max_count = 1
        count = 1
        stk.append((root, False))
        while stk:
            (node, is_visited) = stk.pop()
            if not is_visited:
                if node.right:
                    stk.append((node.right, False))
                stk.append((node, True))
                if node.left:
                    stk.append((node.left, False))
            #在这个逻辑部分,才是真正去处理节点了,所以在这部分修改了pre
            #代表我真的遍历并处理了这个节点
            else:
                if pre:
                    if pre.val == node.val:
                        count += 1
                    else:
                        count = 1
                    if count == max_count:
                        res.append(node.val)
                    elif count > max_count:
                        max_count = count
                        res.clear()
                        res.append(node.val)
                else:
                    res.append(node.val)
                pre = node
        return res

leetcode.538把二叉搜索树转换为累加树

中序是左中右,这题反过来,右中左遍历,然后利用pre做累加就行

递归法:

class Solution:
    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        self.pre = None
        def right_mid_left_traversal(node):
            if not node:
                return
            right_mid_left_traversal(node.right)
            if self.pre:
                node.val += self.pre.val
            self.pre = node
            right_mid_left_traversal(node.left)
        right_mid_left_traversal(root)
        return root

迭代法:

class Solution:
    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root:
            return None
        stk = []
        stk.append((root, False))
        pre = None
        while stk:
            (node, is_visited) = stk.pop()
            #入栈顺序 left mid right
            if not is_visited:
                if node.left:
                    stk.append((node.left, False))
                stk.append((node, True))
                if node.right:
                    stk.append((node.right, False))
            else:
                if pre:
                    node.val += pre.val
                pre = node
        return root

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值