The problem:
Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
My analysis:
The recursion is the best way to solve this kind of problem: At each step, we follow the same pattern to divide the problem into subproblems, and merge the answers together as the original problem. (divide - conqueror)
The problem's pattern is:
1. we find the mid of the given array, and set it as the current tree's root(new a node).
2. we set the left pointer to the result of tree ([low ... mid - 1]).
3. we set the right pointer to the result of tree ([mid + 1 ... high]).
4. then we return the node.
On thing we should be bery careful is the base case.
It's very easy to wrongly write the base case as:
if (low == high) { return TreeNode(num[low]); }
This problem is arisen from the wrong conception that: in binary search(divide), we could always reach the (low == high) as termination condition. In fact this idea is absolutely wrong!!! That's way we use "while(low <= high)" as condition for loop in binary search.
In fact, we could not always reach "low == high", considering following cases:
ret.left = helper(num, low, mid - 1); ret.right = helper(num, mid + 1, high); 1. num[] = [0, 1] low = 0, high = 1, mid = (low + high) / 2 = 0. helper (num, low, mid - 1) ===> helper(num, 0, -1); //low == high could not be used. helper (num, mid + 1, high) ===> helper(num, 1, 1); 2. num[] = [0, 1, 2] low = 0, high = 1, mid = (low + high) / 2 = 1. helper (num, low, mid - 1) ===> helper(num, 0, 0); helper (num, mid + 1, high) ===> helper(num, 1, 1);
From aboving analysis, we could find out that, when the searched array is in odds length, we would meet "low == high".
However, when the array is in even length, we would not meet "low == high".
We could fix this problem by using "low > high" as termination condition.
For this case, we use following base case:
if (low > high) { //we use a violation as base case!!! beautiful! return null; } 1. num[] = [0, 1] low = 0, high = 1, mid = (low + high) / 2 = 0. helper (num, low, mid - 1) ===> helper(num, 0, -1); //violation happens, return null helper (num, mid + 1, high) ===> helper(num, 1, 1); ===> low = 1, high = 1, mid = (low + high) / 2 = 1. helper (num, low, mid - 1) ===> helper(num, 1, 0); //violation happens, return null helper (num, mid + 1, high) ===> helper(num, 2, 1); //violation happens, return null
Thus, we could perfectly reach the right termination state!
My solution:
/** * Definition for binary tree * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Solution { public TreeNode sortedArrayToBST(int[] num) { if (num == null || num.length == 0) return null; return helper(num, 0, num.length - 1); } public TreeNode helper(int[] num, int low, int high) { if (low > high) { return null; } int mid = (low + high) / 2; TreeNode ret = new TreeNode(num[mid]); //partion the num array into two part ret.left = helper(num, low, mid - 1); //point the left child pointer to the left part of the tree ret.right = helper(num, mid + 1, high); //point the right child pointer to the right part of the tree return ret; } }