# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def balanceBST(self, root: TreeNode) -> TreeNode:
# Step 1: Inorder traversal to get sorted values
def inorder(node):
if not node:
return []
return inorder(node.left) + [node.val] + inorder(node.right)
sorted_vals = inorder(root)
# Step 2: Build balanced BST from sorted values
def build_balanced_bst(nums, left, right):
if left > right:
return None
mid = (left + right) // 2
node = TreeNode(nums[mid])
node.left = build_balanced_bst(nums, left, mid - 1)
node.right = build_balanced_bst(nums, mid + 1, right)
return node
return build_balanced_bst(sorted_vals, 0, len(sorted_vals) - 1)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void inorder(TreeNode* node, vector<int>& vals) {
if (!node) return;
inorder(node->left, vals);
vals.push_back(node->val);
inorder(node->right, vals);
}
TreeNode* buildBalancedBST(vector<int>& vals, int left, int right) {
if (left > right) return nullptr;
int mid = (left + right) / 2;
TreeNode* node = new TreeNode(vals[mid]);
node->left = buildBalancedBST(vals, left, mid - 1);
node->right = buildBalancedBST(vals, mid + 1, right);
return node;
}
TreeNode* balanceBST(TreeNode* root) {
vector<int> vals;
inorder(root, vals);
return buildBalancedBST(vals, 0, vals.size() - 1);
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode balanceBST(TreeNode root) {
List<Integer> vals = new ArrayList<>();
inorder(root, vals);
return buildBalancedBST(vals, 0, vals.size() - 1);
}
private void inorder(TreeNode node, List<Integer> vals) {
if (node == null) return;
inorder(node.left, vals);
vals.add(node.val);
inorder(node.right, vals);
}
private TreeNode buildBalancedBST(List<Integer> vals, int left, int right) {
if (left > right) return null;
int mid = (left + right) / 2;
TreeNode node = new TreeNode(vals.get(mid));
node.left = buildBalancedBST(vals, left, mid - 1);
node.right = buildBalancedBST(vals, mid + 1, right);
return node;
}
}
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var balanceBST = function(root) {
const vals = [];
function inorder(node) {
if (!node) return;
inorder(node.left);
vals.push(node.val);
inorder(node.right);
}
inorder(root);
function buildBalancedBST(nums, left, right) {
if (left > right) return null;
const mid = Math.floor((left + right) / 2);
const node = new TreeNode(nums[mid]);
node.left = buildBalancedBST(nums, left, mid - 1);
node.right = buildBalancedBST(nums, mid + 1, right);
return node;
}
return buildBalancedBST(vals, 0, vals.length - 1);
};
You are given the root
of a binary search tree (BST). Your task is to return a balanced version of this BST. A balanced BST is defined as a tree where the depth of the two subtrees of every node never differs by more than one. You must use all the original nodes of the tree (do not create new values or reuse values), and there is always at least one valid solution.
When tackling this problem, we first recognize that a binary search tree can become unbalanced if, for example, nodes are inserted in sorted order, resulting in a tree that resembles a linked list. An unbalanced BST can degrade search performance from O(log n) to O(n). Our goal is to restructure the tree so that it is balanced, while still preserving the BST property (left child < parent < right child) and using all the original nodes.
A brute-force approach might involve repeatedly rotating nodes to try to balance the tree, but this is complex and inefficient. Instead, we notice that an in-order traversal of a BST yields a sorted list of node values. If we can rebuild the tree from this sorted list, always picking the middle element as the root (and recursively for sublists), we will end up with a balanced BST.
This leads us to a two-step approach: first, extract the sorted values using in-order traversal; second, use these values to construct a balanced BST by recursively choosing the middle node as the root of each subtree.
To solve the problem efficiently, we follow these steps:
This method ensures that the tree is as balanced as possible, with a minimal height, and all original node values are reused exactly once.
Let's consider an example where the input BST is unbalanced:
Input BST:
1 \ 2 \ 3 \ 4
The balanced BST will look like:
2 / \ 1 3 \ 4
The final tree is balanced: each node's left and right subtrees differ in height by at most 1.
To balance a binary search tree, the most efficient method is to perform an in-order traversal to extract the sorted node values, then rebuild the tree by recursively choosing the middle element as the root. This guarantees a balanced BST and leverages the properties of BSTs and sorted arrays. The approach is both simple and optimal, running in linear time and space, and is easy to implement in any modern programming language.