1. 题目
https://leetcode.cn/problems/convert-bst-to-greater-tree/
考察点
总结一下这个题目的要点:
- 题目给定一个二叉搜索树,要求把它转换成累加树,即每个节点的值是原来的值加上所有大于它的值之和。
- 为了实现这个转换,我们需要按照节点值降序遍历所有节点,同时记录已经遍历过的节点值的和,并把这个和加到当前节点的值中。
- 这种按照节点值降序遍历的方法被称为反序中序遍历,它可以利用二叉搜索树的性质,即左子树的值小于根节点的值,右子树的值大于根节点的值。
- 反序中序遍历可以用递归,栈或者 Morris 遍历三种方法来实现,它们的思路都是先遍历右子树,再遍历根节点,最后遍历左子树。
- 递归方法是通过调用栈来回溯之前的节点,需要维护一个全局变量来记录节点值的和。
- 栈方法是通过迭代和一个辅助栈来模拟递归过程,需要把当前节点到最右边叶子路径上的点全部压入栈中,然后弹出并更新节点值,再考虑左子树。
- Morris 遍历方法是通过修改二叉搜索树的结构来实现常数空间复杂度的遍历,需要找到当前节点在中序遍历下的前驱节点,并建立临时链接或者断开链接。
2. 解法
有两种常见的解法,
- 一种是使用递归,
- 一种是使用栈。
解法一:使用递归
递归的思路是从右子树开始,用一个变量记录累加和,然后更新每个节点的值,并向左子树递归。
public class Solution1 { /** * Traverse in this order: right -> root -> left */ public TreeNode convertBST(TreeNode root) { dfs(root, 0); // 调用递归函数,初始累加和为 0 return root; // 返回修改后的根节点 } private int dfs(TreeNode root, int val) { if (root == null) { // 如果节点为空,直接返回累加和 return val; } root.val += dfs(root.right, val); // 更新当前节点的值为原值加上右子树的累加和 return dfs(root.left, root.val); // 返回左子树的累加和,即当前节点的值 } }
解法二: 使用栈
栈的思路是用中序遍历的逆序(右 -> 根 -> 左)遍历二叉树,同样用一个变量记录累加和,并更新每个节点的值。‘
public class Solution2 { //This solution is generic for both BST and regular binary trees public TreeNode convertBST(TreeNode root) { if (root == null) { // 如果节点为空,直接返回空 return root; } Stack<TreeNode> stack = new Stack<>(); // 创建一个栈 TreeNode node = root; // 用一个变量 node 记录当前节点 int sum = 0; // 用一个变量 sum 记录累加和 while (!stack.isEmpty() || node != null) { // 当栈不为空或者节点不为空时,循环执行以下操作 // push all nodes up to (and including) this subtree's maximum on // the stack. while (node != null) { // 当节点不为空时,把它压入栈中,并把它的右子节点赋给 node,相当于遍历右子树 stack.push(node); node = node.right; } node = stack.pop(); // 当节点为空时,从栈中弹出一个节点,并赋给 node,相当于访问当前最大的节点 sum += node.val; // 把 sum 加上该节点的值 node.val = sum; // 更新该节点的值为 sum // all nodes with values between the current and its parent lie in // the left subtree. node = node.left; // 把该节点的左子节点赋给 node,相当于遍历左子树 } return root; // 返回修改后的根节点 } }