这里是引用给定一个二叉搜索树,请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。
方法一
反序中序遍历
二叉搜索树的中序遍历是一个单调递增的有序序列。如果我们反序地中序遍历该二叉搜索树,即可得到一个单调递减的有序序列。这样我们只需要反序中序遍历该二叉搜索树,记录过程中的节点值之和,并不断更新当前遍历到的节点的节点值,即可得到题目要求的累加树。
代码
class Solution:
def convertBST(self, root: TreeNode) -> TreeNode:
def dfs(root: TreeNode):
# nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量。
nonlocal total
if root:
convertBST(root.right)
total += root.val
root.val = total
convertBST(root.left)
total = 0
dfs(root)
return root
时间复杂度:O(n),其中 nn 是二叉搜索树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n),为递归过程中栈的开销,平均情况下为O(logn),最坏情况下树呈现链状,为O(n)。
方法二
Morris 遍历
Morris 遍历的核心思想是利用树的大量空闲指针,实现空间开销的极限缩减。其反序中序遍历规则总结如下:
- 如果当前节点的右子节点为空,处理当前节点,并遍历当前节点的左子节点;
- 如果当前节点的右子节点不为空,找到当前节点右子树的最左节点(该节点为当前节点中序遍历的前驱节点);
- 如果最左节点的左指针为空,将最左节点的左指针指向当前节点,遍历当前节点的右子节点;
- 如果最左节点的左指针不为空,将最左节点的左指针重新置为空(恢复树的原状),处理当前节点,并将当前节点置为其左节点;
重复步骤 1 和步骤 2,直到遍历结束。
代码
def convertBST(self, root: TreeNode) -> TreeNode:
def getSuccessor(node: TreeNode) -> TreeNode:
succ = node.right
while succ.left and succ.left != node:
succ = succ.left
return succ
total = 0
node = root
while node:
if not node.right:
total += node.val
node.val = total
node = node.left
else:
succ = getSuccessor(node)
if not succ.left:
succ.left = node
node = node.right
else:
succ.left = None
total += node.val
node.val = total
node = node.left
return root
时间复杂度:O(n),其中 nn 是二叉搜索树的节点数。没有左子树的节点只被访问一次,有左子树的节点被访问两次。
空间复杂度:O(1)。只操作已经存在的指针(树的空闲指针),因此只需要常数的额外空间。