题解:538.把二叉搜索树转换为累加树
题目描述
题目是 LeetCode 的第 538 题: 把二叉搜索树转换为累加树。
给出二叉搜索树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node
的新值等于原树中大于或等于 node.val
的值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。
思路分析
一棵二叉搜索树,如果是中根遍历,那么,其序列正好是一个升序序列。但,题目要求的是大于等于自身的节点值之和。正常的中根遍历是“左中右”,反过来“右中左”,就是降序序列,累计求和就符合题目要求了。
解题代码
中序遍历,可以用栈,也可以使用 Morris 遍历。在 题解:找到二叉搜索树中两个错误的节点 中就是用了 Morris 遍历。网上也很少有反向的 Morris 中根遍历。正好练习一下。
/**
* 基于 Morris 的倒序中根遍历
*
* @author D瓜哥 · https://www.diguage.com
*/
public TreeNode convertBST(TreeNode root) {
int sum = 0;
// 反向 Morris
TreeNode cur = root;
TreeNode mostLeft = null;
while (cur != null) {
// 向右转
mostLeft = cur.right;
if (mostLeft != null) {
// 寻找最左边的节点
while (mostLeft.left != null && mostLeft.left != cur) {
mostLeft = mostLeft.left;
}
if (mostLeft.left == null) {
// 第一次访问,将最左节点的左子树指向当前节点
mostLeft.left = cur;
cur = cur.right;
continue;
} else {
// 第二次访问,掐断中间建立的连接
mostLeft.left = null;
}
}
// 计算累加和
sum += cur.val;
cur.val = sum;
cur = cur.left;
}
return root;
}
得益于 Morris 的优秀本质,这个解法的时间复杂度是: O(n),空间复杂度是: O(1)。
关于 Morris 树遍历的更多介绍,请看: 神奇的 Morris 树遍历。