标签: 树 线段树 二叉搜索树 数组 二分查找 二叉树 有序集合
难度: Medium
标签: 树 线段树 二叉搜索树 数组 二分查找 二叉树 有序集合
难度: Medium
运行时间: 345 ms
内存: 67.8 MB
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def getNumber(self, root: Optional[TreeNode], ops: List[List[int]]) -> int: values = [] def dfs(root): if not root: return dfs(root.left) values.append(root.val) dfs(root.right) dfs(root) ans = 0 for tp, x, y in ops[::-1]: i = bisect.bisect_left(values, x) j = bisect.bisect_right(values, y) if tp == 1: ans += j-i values = values[:i] + values[j:] if not values: break return ans
此题解通过首先将二叉搜索树的所有节点值收集到一个列表中,然后逆序遍历给定的操作列表。对于每个操作,它使用二分搜索确定操作影响的值范围在列表中的位置,然后根据操作类型更新红色节点的计数器。操作完成后,对列表进行切片以删除已处理的值范围。该方法利用了二叉搜索树的有序性和二分搜索来有效处理节点范围。
时间复杂度: O(m log n)
空间复杂度: O(n)
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def getNumber(self, root: Optional[TreeNode], ops: List[List[int]]) -> int: values = [] def dfs(root): if not root: return dfs(root.left) values.append(root.val) # Collect node values in sorted order dfs(root.right) dfs(root) ans = 0 for tp, x, y in ops[::-1]: i = bisect.bisect_left(values, x) j = bisect.bisect_right(values, y) if tp == 1: ans += j-i # Count the nodes to be painted red values = values[:i] + values[j:] # Remove the range of values affected by the operation if not values: break return ans
题解中选择逆序遍历操作列表的原因是为了确保在处理每个操作时,操作影响的节点范围不会被后续的操作影响。如果从后向前应用操作,可以避免在删除或修改节点值范围时对未来操作产生影响。这种方法允许我们在处理每个操作时,只考虑当前操作的影响,而不需要担心后续操作可能对已处理的节点范围造成的干扰。
在逆序遍历操作列表时,直接移除已处理的值范围不会影响后续操作的正确性。由于我们是从操作列表的最后一个操作开始处理,并且每次处理都是针对当前状态下的值范围,所以一旦一个范围被处理(例如染色或计数),它就不再需要被后续的操作考虑。这种方法确保了每个操作都是在一个更新后的环境中独立执行,从而避免了对未来操作的干扰。
题解中使用深度优先搜索(DFS)来收集所有节点值,确实会得到一个有序的列表。这是因为在二叉搜索树(BST)中,如果按照中序遍历(即先遍历左子树,然后访问根节点,最后遍历右子树)的方式进行,遍历得到的值序列是按照从小到大的顺序排列的。因此,DFS在此处确保了值的有序性,这是利用二叉搜索树的性质得到的结果。