Leetcode 刷题第21天 |98,530,501

Leetcode 98 验证二叉搜索树

题目:

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
示例1
输入:root = [2,1,3]
输出:true
示例 2:
示例2

输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。
提示:

  • 树中节点数目范围在[1, 1 0 4 10^4 104] 内
  • - 2 31 2^{31} 231 <= Node.val <= 2 31 2^{31} 231 - 1

前言:

什么是二叉搜索树?简单说:根节点大于左子树上的任何值;小于右子树上的任何值。子树同样满足这样的定义。

算法思想:

  • 递归法:
    (1)利用双指针法:
    递归参数:二叉树根节点
    递归结束条件:当当前节点位None,返回;但无返回值,意思是结束当前递归,返回到上一层。
    注: python中return的作用:
    • 返回值(多个值)
    • 结束当前函数

一次递归逻辑:首先是左递归;中序处理pre(cur的前一个节点)的value 是否严格小于cur(当前节点)的value;递归遍历右子树;
(2)定义最小值法:
思路基本与(1)相似,按照二叉排序树的性质,中序遍历的节点是有序的,也就是递增的。也就是用maxValue记录cur节点前的节点的value,即遍历到cur之前节点的最大值。如果cur.value>maxValue,则更新maxValue;否则返回False,即不满足条件。
2. 迭代法:
依然采用中序遍历,在“中序”处理逻辑处类似递归法。

代码实现:

  1. 递归法:
    (1)双指针法:
# 定义树节点
class TreeNode:
    def __init__(self, val=0, left=None, right=None) -> None:
        self.val = val
        self.left = left
        self.right = right

class Solution:
    # 定义全局指针,指向当前节点的前一个节点
    # 此后双指针法遍历二叉树,判断是否是二叉搜索树
    def __init__(self) -> None:
        self.pre = None
    def isValidBST(self, root):
        if root is None:
            return True
        left = self.isValidBST(root.left)
        # self.pre is not None: 意味着递归到最后一个节点不用和root.val比较
        # self.pre.val >= root.val意味着当前“双指针”开始移动了
        if self.pre is not None and self.pre.val >= root.val:
            return False
        self.pre = root
        right = self.isValidBST(root.right)
        return left and right

(2)maxValue方式:

# 定义树结构
class TreeNode:
    def __init__(self, val=0, left=None, right=None) -> None:
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def __init__(self) -> None:
        self.maxValue = float('-inf')

    def isValidBST(self, root):
        if root is None:
            return True

        left = self.isValidBST(root.left)
        if root.val > maxValue:
            maxValue = root.val
        else:
            return False
        right = self.isValidBST(root.right)
        return left and right
  1. 迭代法:
# 定义树结构
class TreeNode:
    def __init__(self, val=0, left=None, right=None) -> None:
        self.val = val
        self.left = left
        self.right = right

# 利用中序遍历的思想
class Solution:
    def isValidBST(self, root):
        if root is None:
            return True
        stack = []
        pre = None
        cur = root

        while cur or stack:
            # 一路向左
            if cur:
                stack.append(cur)
                cur = cur.left
            else:
                cur = stack.pop()
                if pre is not None and cur.val <= pre.val:
                    return False
                pre = cur
                cur = cur.right
        return True

Leetcode 530 二叉搜索树的最小绝对差

题目:

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
示例 1:
实例1
输入:root = [4,2,6,1,3]
输出:1
示例 2:
实例2
输入:root = [1,0,48,null,null,12,49]
输出:1
提示:

  • 树中节点的数目范围是 [2, 1 0 4 10^4 104]
  • 0 <= Node.val <= 1 0 5 10^5 105

算法思路:

一个常规的想法是,开辟一个数组,中序遍历二叉树(为什么中序?利用二叉搜索树的性质)将二叉树的节点都存放在数组中,然后对数组排序。这样做可以,但是有没有更好的办法呢?

  1. 递归法:
    采用双指针法实现。前文说到,二叉搜索树具备良好的性质,因此,中序遍历二叉树是一种很好的选择。
    pre指针:代表当前节点的前一个节点
    cur指针:代表当前节点
    递归参数:当前二叉树节点
    递归结束条件:如果当前节点为None,则返回。
    一次递归逻辑:按照中序遍历的思想,首先遍历左子树。如果pre 不为None,说明要将pre的值和cur的值作差(在绝对值),然后更新最小值。
    最后递归遍历右子树。
  2. 迭代法:
    按照树的中序遍历算法改动即可,逻辑参照递归法。

代码实现:

  1. 递归法:
# 定义树节点
class TreeNode:
    def __init__(self, val=0, left=None, right=None) -> None:
        self.val = val
        self.left = left
        self.right = right

class Solution:
	# 初始化全局最小值和指针
	# 笔者最开始出现的错误是每次递归都定义一个最小值和指针。
    def __init__(self) -> None:
        self.min_value = float('inf')
        self.pre = None

    def traversal(self, cur):
    # 不要求有返回值,但是要求返回到上一层函数
        if cur is None:
            return
        self.traversal(cur.left)
        if self.pre is not None:
            self.min_value = min(self.min_value, (cur.val - self.pre.val))
        self.pre = cur
        self.traversal(cur.right)
        return self.min_value

    def getMinimumDifference(self, root):
        return self.traversal(root)
  1. 迭代法:
# 定义树节点
class TreeNode:
    def __init__(self, val=0, left=None, right=None) -> None:
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def getMinimumDifference(self, root) -> int:
        min_value = float('inf')
        stack = []
        cur = root
        pre = None
        
        while cur or stack:
        	# 一路向左
            if cur:
                stack.append(cur)
                cur = cur.left
             # 直到左节点位空,出栈栈顶元素。也就是返回到上一层节点
            else:
                cur = stack.pop()
                if pre is not None:
                    min_value = min(min_value, (cur.val - pre.val))
                pre = cur
                stack.append(cur.right)
        return min_value

Leetcode 501 二叉搜索树中的众数

题目:

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
假定 BST 满足如下定义:
结点左子树中所含节点的值 小于等于 当前节点的值
结点右子树中所含节点的值 大于等于 当前节点的值
左子树和右子树都是二叉搜索树
示例 1:
示例1
输入:root = [1,null,2,2]
输出:[2]
示例 2:
输入:root = [0]
输出:[0]
提示:

  • 树中节点的数目在范围 [1, 1 0 4 10^4 104] 内
  • - 1 0 5 10^5 105 <= Node.val <= 1 0 5 10^5 105

算法思想:

  1. 递归法:
    (1)利用python 内置defaultdict
    defaultdict:key是node.value;value为每个value出现的次数;
    递归参数:当前二叉树节点 root
    递归结束条件:当当前数组没有元素时,说明遍历到空节点,返回即结束当前函数
    一次递归逻辑:正常中序递归
    (2)普通计数思想,双指针法
    递归参数和递归结束条件相同
    pre:中序遍历cur节点的前一个节点;cur:当前节点;
    一次递归逻辑:左递归;中序处理;右递归;其中中序处理重点说,如何表示当前是第一个节点?pre为空,cur指向第一个节点,也就是最左侧节点,此时count=1;接下来,如果pre.value = cur.value,说明cur当前指向的值与pre.value相等,count++;否则pre.value != cur.value,说明遇到了一个新的值,count=1。
  2. 迭代法:
    采用中序遍历思想,逻辑与递归法相同,采用双指针法。

代码实现:

  1. 递归法:
    (1)内置defaultdict:
# 定义树节点
from collections import defaultdict
class TreeNode:
    def __init__(self, val=0, left=None, right=None) -> None:
        self.val = val
        self.left = left
        self.rigth = right

class Solution:
    def searchBST(self, cur, freq_map):
        if cur is None:
            return 
        freq_map[cur.val] += 1
        self.searchBST(cur.left, freq_map)
        self.searchBST(cur.right, freq_map)

    def findMode(self, root):
        freq_map = defaultdict(int)
        result = []
        if root is None:
            return result
        self.searchBST(root, freq_map)
        max_freq = max(freq_map.values())
        for key, freq in freq_map.items():
            if freq == max_freq:
                result.append(key)
        return result

(2)双指针法:

# 定义树节点
class TreeNode:
    def __init__(self, val=0, left=None, right=None) -> None:
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def __init__(self) -> None:
        self.maxCount = 0
        self.count = 0
        self.pre = None
        self.result = []

    def searchBST(self, cur):
        if cur is None:
            return
        self.searchBST(cur.left)
        if self.pre is None:
            self.count += 1
        elif self.pre.val == cur.val:
            self.count += 1
        else:
            self.count = 1
        self.pre = cur
        if self.count == self.maxCount:
            self.result.append(cur.val)
        
        if self.count > self.maxCount:
            self.maxCount = self.count
            self.result = [cur.val]
        self.searchBST(cur.right)  
        return
        
    def findMode(self, root):
        self.maxCount = 0
        self.count = 0
        self.pre = None
        self.result = []

        self.searchBST(root)
        return self.result
  1. 迭代法:
# 定义树节点
class TreeNode:
    def __init__(self, val=0, left=None, right=None) -> None:
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def findMode(self, root):
        stack = []
        result = []
        pre = None
        maxCount = 0
        count = 0
        cur = root

        while cur or stack:
            if cur:
                stack.append(cur)
                cur = cur.left
            else:
                cur = stack.pop()
                if pre is None:     # 处理第一个节点
                    count = 1
                elif cur.val == pre.val:    # 与前一个节点的值相同
                    count += 1
                else:
                    count = 1       # 与前一个节点的值不同,重新置为1
                pre = cur
                if count == maxCount:
                    result.append(cur.val)
                if count > maxCount:
                    maxCount = count
                    result = [cur.val]
                pre = cur
                cur = cur.right
        return result
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值