各位题友大家好! 今天是 @负雪明烛 坚持日更的第 88 天。今天力扣上的每日一题是「938. 二叉搜索树的范围和」。
解题思路
本题重点:二叉搜索树,最重要性质:二叉搜索树的中序遍历是有序的。
本题没有直接使用有序的性质,而是使用了二叉搜索树的定义:每个节点的所有左子树都小于当前节点;每个节点的所有右子树都大于当前节点。
直接递归
假如题目给出的是一棵普通的二叉树,是如何求所有在 [low, high]
之间的节点值的和呢?我们可以使用递归对所有节点遍历一次,前序、中序、后序均可,累加所有节点值在 [low, high]
之间的节点值。
要写出递归,最基本的就是要清晰地理解并记住递归函数的定义。
比如下面的代码中,我直接用的题目给出的 rangeSumBST(root, low, high)
作为递归函数,它的含义是寻找以 root
为根节点的所有 [low, high]
范围内的节点值之和。
- 如果当前 root 值在 [low, high] 之间就加上 root.val;
- 然后要分别加上 root 的左、右子树中所有在
[low, high]
范围内的节点之和(此时发现恰好符合rangeSumBST()
函数的定义,于是直接调用rangeSumBST()
)。
如果没理解定义的递归函数的含义是什么,那怎么可能写出正确的递归呢?换个说法,如果没理解代码里面的每个函数或者变量的含义是什么,那怎么可能写出正确的代码呢?
代码如下:
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def rangeSumBST(self, root, low, high):
res = 0
if not root:
return res
res += self.rangeSumBST(root.left, low, high)
if low <= root.val <= high:
res += root.val
res += self.rangeSumBST(root.right, low, high)
return res
剪枝
上面的代码中是题目输入的是普通二叉树来进行计算的,其实题目给出的是个二叉搜索树,所以可以根据其性质进行剪枝。
- 二叉搜索树的左子树一定比 root 小,因此如果 root.val <= low,那么不用继续搜索左子树;
- 二叉搜索树的右子树一定比 root 大,因此如果 root.val >= high,那么不用继续搜索右子树。
经过剪枝的递归,能减少搜索的空间。因此在树特别庞大的时候,速度更快。
代码如下。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def rangeSumBST(self, root, low, high):
res = 0
if not root:
return res
if root.val > low:
res += self.rangeSumBST(root.left, low, high)
if low <= root.val <= high:
res += root.val
if root.val < high:
res += self.rangeSumBST(root.right, low, high)
return res
- 时间复杂度:$O(N)$,因为每个节点都要遍历一次;
- 空间复杂度:$O(N)$,因为递归需要消耗系统栈。
刷题心得
树的题目,一般都可以用递归解决。在写递归的时候,一定先明白递归函数的含义,然后才能写出正确的代码。
OK,以上就是 @负雪明烛 写的今天题解的全部内容了,如果你觉得有帮助的话,求赞、求关注、求收藏。如果有疑问的话,请在下面评论,我会及时解答。
关注我,你将不会错过我的精彩动画题解、面试题分享、组队刷题活动,进入主页 @负雪明烛 右侧有刷题组织,从此刷题不再孤单。
祝大家 AC 多多,Offer 多多!我们明天再见!