1、深度遍历
考虑到我们使用的是二叉搜索树,右子树中的值总比左子树中的值大。因此我们可以按照“右根左”的顺序遍历每一个节点并将节点的和进行累加,而后将累加的值赋给每一个节点即可。
class Solution {
public:
int dfs(TreeNode *root, int tempSum) {
if (!root) return tempSum;
tempSum = dfs(root->right, tempSum);
tempSum = tempSum + root->val;
root->val = tempSum;
tempSum = dfs(root->left, tempSum);
return tempSum;
}
TreeNode *convertBST(TreeNode *root) {
dfs(root, 0);
return root;
}
};
或
class Solution {
public:
int tempSum = 0;
TreeNode *convertBST(TreeNode *root) {
if (root != nullptr) {
convertBST(root->right);
tempSum += root->val;
root->val = tempSum;
convertBST(root->left);
}
return root;
}
};
2、Morris 遍历
考虑到我们在对二叉树进行遍历时,无论是递归还是迭代都会占用O(n)的空间复杂度,因此我们可以使用Morris 遍历对二叉树的遍历进行优化,将空间复杂度降低到O(1)。
Morris 遍历之所以能降低空间复杂度在于其利用了未使用到的节点的空指针。由于本题中我们采用反序中序遍历进行搜索,我们可以这样进行Morris 遍历:1、当当前节点的右子节点为空时,说明当前节点是最右的节点,我们处理当前节点并遍历当前节点的左子节点;2、当当前节点的右子节点不为空时,我们找到当前节点右子树中的最左节点(显然该节点的左指针一定为空),此时我们将其左指针指向当前节点,这样我们就能够通过左指针直接抵达根节点而不需要通过栈来实现,而后我们继续遍历当前节点的右子节点。若此时最左节点的左指针不为空,说明此时当前的最左节点的左指针指向当前节点,此时我们先将最左节点的左指针置为空并对当前节点进行处理,而后将当前节点更新为当前节点的左子节点即通过指针回到当前节点对应的上一个根节点或左子树节点。
class Solution {
public:
TreeNode* getSuccessor(TreeNode* node) {
TreeNode* succ = node->right;
while (succ->left != nullptr && succ->left != node) {
succ = succ->left;
}
return succ;
}
TreeNode* convertBST(TreeNode* root) {
int sum = 0;
TreeNode* node = root;
while (node != nullptr) {
if (node->right == nullptr) {
sum += node->val;
node->val = sum;
node = node->left;
} else {
TreeNode* succ = getSuccessor(node);
if (succ->left == nullptr) {
succ->left = node;
node = node->right;
} else {
succ->left = nullptr;
sum += node->val;
node->val = sum;
node = node->left;
}
}
}
return root;
}
};