15.5 Convert Sorted Array to Binary Search Tree

优质
小牛编辑
134浏览
2023-12-01

Question

Given an array where elements are sorted in ascending order,
convert it to a height balanced BST.

Given a sorted (increasing order) array,
Convert it to create a binary tree with minimal height.

Example
Given [1,2,3,4,5,6,7], return

     4
   /   \
  2     6
 / \    / \
1   3  5   7
Note
There may exist multiple valid solutions, return any of them.

题解 - 折半取中

将二叉搜索树按中序遍历即可得升序 key 这个容易实现,但反过来由升序 key 逆推生成二叉搜索树呢?按照二叉搜索树的定义我们可以将较大的 key 链接到前一个树的最右侧节点,这种方法实现极其简单,但是无法达到本题「树高平衡-左右子树的高度差绝对值不超过1」的要求,因此只能另辟蹊径以达到「平衡二叉搜索树」的要求。

要达到「平衡二叉搜索树」这个条件,我们首先应从「平衡二叉搜索树」的特性入手。简单起见,我们先考虑下特殊的满二叉搜索树,满二叉搜索树的一个重要特征就是各根节点的 key 不小于左子树的 key ,而小于右子树的所有 key;另一个则是左右子树数目均相等,那么我们只要能将所给升序序列分成一大一小的左右两半部分即可满足题目要求。又由于此题所给的链表结构中仅有左右子树的链接而无指向根节点的链接,故我们只能从中间的根节点进行分析逐层往下递推直至取完数组中所有 key, 数组中间的索引自然就成为了根节点。由于 OJ 上方法入口参数仅有升序序列,方便起见我们可以另写一私有方法,加入startend两个参数,至此递归模型初步建立。

C++

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode *sortedArrayToBST(vector<int> &num) {
        if (num.empty()) {
            return NULL;
        }

        return middleNode(num, 0, num.size() - 1);
    }

private:
    TreeNode *middleNode(vector<int> &num, const int start, const int end) {
        if (start > end) {
            return NULL;
        }

        TreeNode *root = new TreeNode(num[start + (end - start) / 2]);
        root->left = middleNode(num, start, start + (end - start) / 2 - 1);
        root->right = middleNode(num, start + (end - start) / 2 + 1, end);

        return root;
    }
};

Java

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
    /**
     * @param A: an integer array
     * @return: a tree node
     */
    public TreeNode sortedArrayToBST(int[] A) {
        if (A == null || A.length == 0) return null;

        return helper(A, 0, A.length - 1);
    }

    private TreeNode helper(int[] nums, int start, int end) {
        if (start > end) return null;

        int mid = start + (end - start) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = helper(nums, start, mid - 1);
        root.right = helper(nums, mid + 1, end);

        return root;
    }
}

源码分析

从题解的分析中可以看出中间根节点的建立至关重要!由于数组是可以进行随机访问的,故可取数组中间的索引为根节点,左右子树节点可递归求解。虽然这种递归的过程和「二分搜索」的模板非常像,但是切记本题中根据所给升序序列建立平衡二叉搜索树的过程中需要做到不重不漏,故边界处理需要异常小心,不能再套用start + 1 < end的模板了。

复杂度分析

递归调用middleNode方法时每个key被访问一次,故时间复杂度可近似认为是 $$O(n)$$.

Reference