[leetcode javascript]938. 二叉搜索树的范围(部分遍历、全部遍历) 和 897. 递增顺序查找树(递归、辅助栈)

目录

938. 二叉搜索树的范围和

方法一:部分遍历

方法二:全部遍历

897. 递增顺序查找树

方法一:224ms

方法二:332ms

方法三:348ms

方法四:(辅助栈)


 

938. 二叉搜索树的范围和

题解: 递归(思路非常清晰,内含画解,强推!)和  中序排序 递归 将整棵树遍历一遍 

方法一:部分遍历

思路
标签:深度优先遍历
题意:这个题字面含义很难理解,本意就是求出所有 X >= L 且 X <= R 的值的和
递归终止条件:
       当前节点为 null 时返回 0
       当前节点 X < L 时则返回右子树之和
       当前节点 X > R 时则返回左子树之和
       当前节点 X >= L 且 X <= R 时则返回:当前节点值 + 左子树之和 + 右子树之和
注意点:通过判断X的大小能够避免遍历全部树的节点,比如下方的动图中,3 这个值就没有必要遍历

 

// 并没有将整棵树遍历一遍
var rangeSumBST = function(root, L, R) {
    if(!root)return 0;
    if(root.val < L)return rangeSumBST(root.right, L, R);//根节点小于L,那就看它的右结点,因为右结点值比根节点大。左结点不用考虑了。
    if(root.val > R)return rangeSumBST(root.left, L, R);
    return root.val + rangeSumBST(root.right, L, R) + rangeSumBST(root.left, L, R);
};

// 用一个思路,这次没有新建sum,直接靠return
var rangeSumBST = function(root, L, R) {
    // let sum = 0;
    return range(root, L, R);
    // return sum;
    
    function range(root, L, R){
        if(!root)return 0;
        if(root.val < L)return range(root.right, L, R);
        if(root.val > R)return range(root.left, L, R);
        return root.val + range(root.right, L, R) + range(root.left, L, R);
    }
    
};


// 同一个思路,但新建了另一个函数
var rangeSumBST = function(root, L, R) {
    let sum = 0;
    range(root, L, R);
    return sum;
    
    function range(root, L, R){
        if(!root)return 0;
        if(root.val < L)return range(root.right, L, R);
        if(root.val > R)return range(root.left, L, R);
        // 改的时候曾写过:sum = root.val + range(root.right, L, R) +  range(root.left, L, R),这个是会出错的,sum = NAN
        sum = sum + root.val;
        range(root.right, L, R);
        range(root.left, L, R);        
    }

};

我以为没有将整棵树遍历一遍运行速度就会比较快,但是第一个代码是336ms,我以为慢的原因是递归了题目给我的函数,于是新建了一个函数,结果才320ms。下面的遍历整棵树,用先序的话会快到260ms左右...神奇了

方法二:全部遍历

// 将整棵树遍历一遍
var rangeSumBST = function(root, L, R) {
    let sum = 0;
    const inOrderNode = (node) => {
        if(!node)return 0;//这个条件要放在递归前面,因为如果node是空,那node.left是不确定的。
        // inOrderNode(node.left);//放在这里是中序遍历
        if(node.val >= L && node.val <= R){
            sum += node.val;
        }
        inOrderNode(node.left);//貌似放在这里,当先序遍历时比较快
        inOrderNode(node.right);

    }
    inOrderNode(root);
    return sum;
}

897. 递增顺序查找树

方法一:224ms

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var increasingBST = function(root) {
    let res = [];
    inOrderNode(root);
    for(var i = 0; i < res.length-1; i++){//注意要用var,如果按我的思路(即,最后那个节点特殊处理)的话用let会错
        res[i].left = null;
        res[i].right = res[i+1];
    }
    // 最后那个节点
    res[i].left = res[i].right = null;
    
    // 注意要从0开始,为什么?不知道...可能是因为要求返回的是一个根节点叭
    return res[0];

    // 注意存的是节点
    function inOrderNode(root){
        if(!root)return null;
        inOrderNode(root.left);
        res.push(root);
        inOrderNode(root.right);
    }
};

下面那个代码和上面是一样的,只是为了留给自己看自己当时是怎么走了弯路的...

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var increasingBST = function(root) {
    let res = [];
    inOrderNode(root);
    for(var i = 0; i < res.length-1; i++){//注意要用var,如果按我的思路let会错
        res[i].left = null;
        res[i].right = res[i+1];
    }
    // 最后那个节点
    res[i].left = res[i].right = null;
    
    //都不需要诶。注意res也是树就好了。
    // let apple = [];
    // preOrderNode(res[0]);//这句!!赶紧记住!res这个树是这么用的
    // console.log(apple);
    // for(let j = 0; j < res.length; j++){
    //     apple.push(res[j].val, res[j].left);
    // }
    // console.log(apple);
    
    // 注意要从0开始,为什么?不知道...可能是因为要求返回的是一个根节点叭
    return res[0];

    // 注意存的是节点
    function inOrderNode(root){
        if(!root)return null;
        inOrderNode(root.left);
        res.push(root);
        inOrderNode(root.right);
    }
    // console.log(res);
    // function preOrderNode(root){
    //     if(!root){
    //         apple.push(null);
    //         return null;
    //     }
    //     apple.push(root.val);
    //     preOrderNode(root.left);
    //     preOrderNode(root.right);
    // }
};

方法二:332ms

根据官方题解方法一做的

// 越来越慢...332ms
var increasingBST = function(root) {
    let res = [];
    inOrderNode(root);
    console.log(res);
    let ans = new TreeNode();
    let cur = ans;
    for(let i of res){
        cur.right = new TreeNode(i);
        cur = cur.right;
    }
    return ans.right;
    
    function inOrderNode(root){
        if(!root)return null;
        inOrderNode(root.left);
        res.push(root.val);
        inOrderNode(root.right);
    }
}

方法三:348ms

 根据官方题解方法二做的  348ms(这么慢吗

var increasingBST = function(root) {
    // 和let res = new TreeNode();结果一样
    // let res = {
    //     left : null,
    //     right : null
    // };
    let res = new TreeNode();
    let cur = res;
    inOrderNode(root);
    
    return cur.right;
    //不加right:[undefined,null,1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9]
    //加了right:[1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9]

    // 注意存的是节点
    function inOrderNode(node){
        if(!node)return null;
        inOrderNode(node.left);
        node.left = null;
        res.right = node;
        res = node;
        inOrderNode(node.right);
    }
};

方法四:(辅助栈)

var increasingBST = function(root) {
    let s = [];
    let res = new TreeNode();
    let p = res;
    
    while(root || s.length){//之前出错原因:将s.length简写成s。后者是c语言的想法,判断s是否为空。但是js中判断非空是看s栈的长度是否为0
        if(root){
            s.push(root);
            root = root.left;
        }else{
            let cur = s.pop();
            root = cur.right;
            cur.left = null;
            p.right = cur;
            p = p.right;
        }
    }
    return res.right;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值