「前端刷题」108. 将有序数组转换为二叉搜索树

92 阅读1分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。

题目

链接:leetcode-cn.com/problems/co…

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

示例 1:

**输入:**nums = [-10,-3,0,5,9] 输出:[0,-3,9,-10,null,5] 解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:

示例 2:

**输入:**nums = [1,3] 输出:[3,1] 解释:[1,3] 和 [3,1] 都是高度平衡二叉搜索树。

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums严格递增 顺序排列

思路

  先简单说说常规解法,因为数组是严格的升序数组,然后根据BST的特性,我们只要将数组以中间索引为界划分成左,右两个数组分别对应着当前节点的left和right,中间索引的值为当前节点的值。
接下来让题目升级一下,如果数组是无序的(不含重复元素),我们该如何建立这个BBST。如果没学习过AVL树(BBST)的小伙伴可以看一看,下面给出BBST的代码。核心是树节点的旋转

详细看代码注释:

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number[]} nums
 * @return {TreeNode}
 */
var sortedArrayToBST = function(nums) {
    if(nums.length == 0) return null;
    let index = Math.floor(nums.length / 2),
        node = new TreeNode(nums[index]);
    node.left = sortedArrayToBST(nums.slice(0, index));
    node.right = sortedArrayToBST(nums.slice(index + 1));
    return node;
};

function arrayToBBST(nums){
    let avlTree = new AVLTree();
    for(let i = 0; i < nums.length; i++){
        avlTree.insert(nums[i]);
    }
    return avlTree.root;
}

// AVL树节点
class AVLTreeNode {
    constructor(val){
        this.val = val;
        this.left = this.right = null;
        this.height = 1;
    }
}
// 平衡状态
const BLANCE_STATE = {
    UNBALANCE_LEFT: 2,
    UNBALANCE_RIGHT: -2,
    SLIGHT_UNBALANCE_LEFT: 1,
    SLIGHT_UNBALANCE_RIGHT: -1,
    BALANCE: 0
}
// AVLTree
class AVLTree {
    constructor(){
        this.root = null;
    }

    _getHeight(node){
        return node != null ? node.height : 0;
    }

    // 有节点发生位置变化的都要更新Height(旋转)
    _updateHeigh(node){
        node.height = Math.max(this._getHeight(node.left), this._getHeight(node.right)) + 1;
        return node;
    }

    _getBalanceState(node){
        return this._getHeight(node.left) - this._getHeight(node.right);
    }

    // 返回值的高度也变化了,但是返回值统一在blance中改变
    _leftRotate(node){
        let res = node.right;
        node.right = res.left;
        res.left = this._updateHeigh(node);
        return res;
    }
    // 返回值的高度也变化了,但是返回值统一在blance中改变
    _rightRotate(node){
        let res = node.left;
        node.left = res.right;
        res.right = this._updateHeigh(node);
        return res;
    }
    // 返回值的高度也变化了,但是返回值统一在blance中改变
    _leftRightRotate(node){
        node.left = this._updateHeigh(this._leftRotate(node.left));
        return this._rightRotate(node);
    }
    // 返回值的高度也变化了,但是返回值统一在blance中改变
    _rightLeftRotate(node){
        node.right = this._updateHeigh(this._rightRotate(node.right));
        return this._leftRotate(node);
    }

    insert(val){
        this.root = this._insertNode(this.root, val);
    }

    _insertNode(node, val){
        if(node == null) return new AVLTreeNode(val);
        if(node.val == val) return node;
        if(node.val < val){
            node.right = this._insertNode(node.right, val);
        }else if(node.val > val){
            node.left = this._insertNode(node.left, val);
        }
        // 判断是否需要平衡,并进行平衡
        return this._doBalance(node);
    }

    search(val){
        let node = this.root;
        while(node){
            if(node.val == val) return node;
            else if(node.val < val) node = node.right;
            else if(node.val > val) node = node.left;
        }
        return null;
    }

    getPre(val){
        let res = null,
            node = this.root;
        while(node){
            if(node.val >= val) node = node.left;
            else if(node.val < val){
                res = node;
                node = node.right;
            }
        }
        return res;
    }

    getNext(val){
        let res = null,
            node = this.root;
        while(node){
            if(node.val <= val) node = node.right;
            else if(node.val > val){
                res = node;
                node = node.left;
            }
        }
        return res;
    }

    remove(val){
        let node = this.search(val);
        if(node == null) return false;
        this.root = this._removeNode(this.root, val);
        return true;
    }

    _removeNode(node, val){
        if(node.val > val) node.left = this._removeNode(node.left, val);
        else if(node.val < val) node.right = this._removeNode(node.right, val);
        else if(node.val == val){
            if (node.left == null) return node.right;
            else if(node.right == null) return node.left;
            else{
                let next = this.getNext(val);
                node.val = next.val;
                // 转为删除next节点
                node.right = this._removeNode(node.right, node.val);
            }

        }
        return this._doBalance(node);
    }

    _doBalance(node){
        if(node == null) return null;
        const balanceState = this._getBalanceState(node);
        // 左侧偏重
        if(balanceState == BLANCE_STATE.UNBALANCE_LEFT){
            // 判断是否需要二次旋转
            const leftNodeBalanceState = this._getBalanceState(node.left);
            if(leftNodeBalanceState == BLANCE_STATE.SLIGHT_UNBALANCE_RIGHT){
                return this._updateHeigh(this._leftRightRotate(node))
            }else{
                return this._updateHeigh(this._rightRotate(node));
            }
        // 右侧偏重
        }else if(balanceState == BLANCE_STATE.UNBALANCE_RIGHT){
            // 判断是否需要二次旋转
            const rightNodeBalanceState = this._getBalanceState(node.right);
            if(rightNodeBalanceState == BLANCE_STATE.SLIGHT_UNBALANCE_LEFT){
                return this._updateHeigh(this._rightLeftRotate(node));
            }else{
                return this._updateHeigh(this._leftRotate(node));
            }
        }
        return this._updateHeigh(node);
    }
}