超琐碎 ≈ 完整记录 + 深入探究 + 任性吐槽
问题地址,难度:Normal,标签:Tree
若有错误之处请予以指正:)
问题描述
Given the root node of a binary search tree, return the sum of values of all nodes with value between L and R (inclusive).
The binary search tree is guaranteed to have unique values.
Example 1:
Input: root = [10,5,15,3,7,null,18], L = 7, R = 15
Output: 32
Example 2:
Input: root = [10,5,15,3,7,13,18,1,null,6], L = 6, R = 10
Output: 23
Note:
The number of nodes in the tree is at most 10000.
The final answer is guaranteed to be less than 2^31.
题意分析
这道题需要了解二叉搜索树的定义,以及递归/循环的知识。
我的实现及调优过程
方法1:356 ms
方法1我的思路是先看[L, R]
这个range能不能卡住当前节点,即当前节点值v
在[L,R]
内。
- 如果在
[L,R]
内,当前的range_sum = (v
+ 左子树range_sum + 右子树rang_sum) - 如果不在
[L,R]
内- 如果整个
[L,R]
都在v
右边,那么:当前的range_sum = 右子树range_sum - 如果整个
[L,R]
都在v
左边,那么:当前的range_sum = 左子树range_sum
- 如果整个
这样从根节点向下,每一个被遍历节点的range_sum都被算出来,最后加回到根节点。注意不是所有节点都会被遍历,因为v不在[L,R]
内的情况下,接下去只会看其左右子树之一。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def rangeSumBST(self, root, L, R):
"""
:type root: TreeNode
:type L: int
:type R: int
:rtype: int
"""
range_sum = getRangeSum(root, L, R)
return range_sum
def getRangeSum(node, L, R):
if node is None:
return 0
if node.val > R:
range_sum = getRangeSum(node.left, L, R)
elif node.val < L:
range_sum = getRangeSum(node.right, L, R)
else:
range_sum = node.val + \
getRangeSum(node.left, L, R) + \
getRangeSum(node.right, L, R)
return range_sum
- 时间复杂度:O(n) (
n
为树的节点数,最坏情况下每个节点都被遍历) - 空间复杂度:O(m) (递归本身的栈会占用一些资源,
m
为树的深度,影响栈的数量)
方法2:356 ms
方法2是Leetcode上的Solution,思路是先初始化了一个self.ans
为0,然后逐个遍历节点,每遇到一个在[L,R]
内的节点,就做一次加法累进self.ans
。
具体的做法:
- 判断当前节点是否在
[L,R]
内,在的话self.ans
加上当前节点值,不在的话继续步骤2和3 - 判断左子树是否可能存在符合要求的节点。根据二叉搜索树定义,左子树中任意的节点
w
都满足w
<v
,而我们要的节点要求是[L, R]
。如果L
<v
,那么可能存在w
>=L
,即w
落在[L, v)
范围内,这时只要再满足w
<=R
(v
<=R
ORw
<=R
),w
就落进了[L,R]
。注意须同时满足三个条件:L
<v
ANDw
>=L
AND (v
<=R
OR w<=
R),第一个条件使用if
确保,但由于我们在该步还没有访问w
,无法确定第二、三个条件的真假,所以继续搜索左子树 - 同样地,考虑与2中相似的情况,我们在该步无法判断
w
<=R
的真假,所以继续搜索右子树
注意这种方法同样不一定会遍历所有节点。同时可以看到,这种解法的实现逻辑看似比上一种简单,但是需要经过严密的分析才能证明其正确性。另外引用王垠的观点,这种连续几个if没有else的写法也是有风险的(终于为自己为什么没有想到这种解法找到了充分理由LOL)
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def rangeSumBST(self, root, L, R):
def dfs(node):
if node:
if L <= node.val <= R:
self.ans += node.val
if L < node.val:
dfs(node.left)
if node.val < R:
dfs(node.right)
self.ans = 0
dfs(root)
return self.ans
- 时间复杂度:O(n) (
n
为树的节点数,最坏情况下每个节点都被遍历) - 空间复杂度:O(m) (递归本身的栈会占用一些资源,
m
为树的深度,影响栈的数量)