Leetcode Python超琐碎笔记: 938. Range Sum of BST

超琐碎 ≈ 完整记录 + 深入探究 + 任性吐槽

问题地址,难度: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

具体的做法:

  1. 判断当前节点是否在[L,R]内,在的话self.ans加上当前节点值,不在的话继续步骤2和3
  2. 判断左子树是否可能存在符合要求的节点。根据二叉搜索树定义,左子树中任意的节点w都满足w<v,而我们要的节点要求是[L, R]如果L<v,那么可能存在w>=L,即w落在[L, v)范围内,这时只要再满足w<=R(v<=R OR w<=R)w就落进了[L,R]。注意须同时满足三个条件:L<v AND w>=L AND (v<=R OR w<=R),第一个条件使用if确保,但由于我们在该步还没有访问w,无法确定第二、三个条件的真假,所以继续搜索左子树
  3. 同样地,考虑与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为树的深度,影响栈的数量)

你可能感兴趣的:(Leetcode Python超琐碎笔记: 938. Range Sum of BST)