跟着代码随想录练算法——二叉树(JS)(下)

跟着代码随想录练算法——二叉树

106. 从中序与后序遍历序列构造二叉树
  • 当中序遍历和后序遍历都为空时,返回null
  • 当中序遍历和后序遍历只有一个值时,构造根节点,返回根节点即可
  • 拿出后序遍历最后一个元素,这个是当前根节点的val,根据它去分割中序序列,分成左子树的中序结果右子树的中序结果
  • 由于中序和后序的序列长度一定是相等的,于是可以根据上一步分割出来的左子树的中序结果和右子树的中序结果的长度来分割后序序列,分为左子树的后序结果右子树的后序结果
  • 根据前面两部得到的左右子树的中序和后序来递归建立左子树和右子树
/**
 * 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 {number[]} inorder
 * @param {number[]} postorder
 * @return {TreeNode}
 */
var buildTree = function(inorder, postorder) {
    if(inorder.length == 0) return null
    let rootValue = postorder[postorder.length - 1]
    let root = new TreeNode(rootValue)
    if(postorder.length == 1) return root
    let i
    for(i = 0; i < inorder.length; i++){
        if(inorder[i] == rootValue) break
    }
    let inLeft = inorder.slice(0, i)
    let inRight = inorder.slice(i + 1)
    // console.log('inLeft,  inRight:',inLeft,  inRight)
    let lenLeft = inLeft.length
    let lenRight = inRight.length
    let postleft = postorder.slice(0, lenLeft)
    let postRight = postorder.slice(lenLeft, lenLeft + lenRight)
    // console.log('postleft,  postRight:',postleft,  postRight)
    root.left = buildTree(inLeft, postleft)
    root.right = buildTree(inRight, postRight)
    return root
};
105. 从前序与中序遍历序列构造二叉树

与上一题类似,只是根节点的值取自前序序列的第一个元素,需要注意左右子树的前序序列分割的边界下标。

/**
 * 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 {number[]} preorder
 * @param {number[]} inorder
 * @return {TreeNode}
 */
var buildTree = function(preorder, inorder) {
    if(preorder.length === 0) return null
    let rootVal = preorder[0]
    let root  = new TreeNode(rootVal)
    if(preorder.length === 1) return root
    let i
    for(i = 0; i < inorder.length; i++){
        if(inorder[i] == rootVal) break
    }
    let inLeft = inorder.slice(0, i)
    let inRight = inorder.slice(i + 1)
    let lenLeft = inLeft.length
    let lenRight = inRight.length
    let preLeft = preorder.slice(1, 1 + lenLeft)
    let preRight = preorder.slice(1 + lenLeft)
    root.left = buildTree(preLeft, inLeft)
    root.right = buildTree(preRight, inRight)
    return root
};
654. 最大二叉树
  • 当 nums 中只有一个元素时:则到了叶子结点,直接返回构造出的叶子结点
  • 当 nums 中元素大于1个时:
    • 找到nums中的最大元素和它的下标
    • 构造最大元素节点
    • 分割数组
    • 递归构造当前节点左子树和右子树
    • 返回节点
/**
 * 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 {number[]} nums
 * @return {TreeNode}
 */
var constructMaximumBinaryTree = function(nums) {
    if(nums.length === 1){
        let node = new TreeNode(nums[0])
        return node
    }
    let max = nums[0]
    let index = 0
    for(let i = 1; i <nums.length; i++){
        if(nums[i] > max){
            max = nums[i]
            index = i
        }
    }
    let node = new TreeNode(max)
    let left = nums.slice(0, index)
    if(left.length > 0) node.left = constructMaximumBinaryTree(left)
    let right = nums.slice(index+1)
    if(right.length > 0) node.right = constructMaximumBinaryTree(right)
    return node
};
617. 合并二叉树
  • 当 root1 为 null 时则返回root2(如果此时2也是null,也没关系,相当于返回null)
  • 当 root2 为 null 时则返回root1
  • root1,2都不是null时,将2对应的val加到1上
  • 递归左子树和右子树
  • 返回root1
/**
 * 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} root1
 * @param {TreeNode} root2
 * @return {TreeNode}
 */
var mergeTrees = function(root1, root2) {
    if(!root1) return root2
    if(!root2) return root1
    root1.val = root1.val + root2.val
    root1.left = mergeTrees(root1.left, root2.left)
    root1.right = mergeTrees(root1.right, root2.right)
    return root1 
};
700. 二叉搜索树中的搜索
  • 当前节点为null或者当前节点的val和目标val相等,则返回当前节点
  • 如果目标val大于当前节点val ,返回递归右子树的节点
  • 如果目标val消于当前节点val ,返回递归左子树的节点
/**
 * 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
 * @param {number} val
 * @return {TreeNode}
 */
var searchBST = function(root, val) {
    if(!root || root.val == val) return root
    if(val > root.val) return searchBST(root.right, val)
    if(val < root.val) return searchBST(root.left,val)
};
98. 验证二叉搜索树

搜索二叉树的中序遍历结果是递增的

/**
 * 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 {boolean}
 */
var isValidBST = function(root) {
    let ans = []
    function dfs(node){
        if(!node) return
        dfs(node.left)
        ans.push(node.val)
        dfs(node.right)
    }
    dfs(root)
    for(let i = 1; i < ans.length; i++ ){
        if(ans[i] <= ans[i-1]) return false
    }
    return true
};

也可以在递归的过程中判断:

  • 如果当前节点是null,返回true
  • 递归左子树
  • pre用来记录中序遍历当前节点的前一个节点,如果当前节点值小于等于pre的值,返回false
  • 递归右子树
  • 左右子树都是搜索二叉树,返回true
var isValidBST = function(root) {
    let pre = null
    function fn(node){
        if(!node) return true
        let left = fn(node.left)
        if(pre && node.val <= pre.val) return false
        pre = node
        let right = fn(node.right)
        return left && right
    }
    return fn(root)
};
530. 二叉搜索树的最小绝对差
  1. 可以先中序遍历二叉树,得到递增数组,然后在这个数组上求得最小绝对值

  2. 也可以在中序遍历时记录上一个节点pre,以及当前节点和上一个节点的差值,更新差值

    这里实现一下方法2

/**
 * 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 {number}
 */
var getMinimumDifference = function(root) {
    let pre = null
    let min = 100001
    function fn(node){
        if(!node) return
        fn(node.left)
        if(pre && node.val - pre.val< min) min = node.val - pre.val
        pre = node
        fn(node.right)
    }
    fn(root)
    return min
};
501. 二叉搜索树中的众数

可以先得到中序遍历数组然后再数组上操作,也可以在遍历时操作,这里选择后者

ans 存返回的众数结果,max 存最多次数,pre 是中序对应的前一个节点,count 用于计数

如果当前节点val等于pre的val,则计数器 + 1,

如果当前节点val不等于pre,比较当前计数器与max比较:

  • count大于max,则先清空ans,然后将pre对应的值放入ans,再更新max为当前count
  • count等于max,将pre对应的值push进ans
  • 小于则忽略

最后还要再加一次判断

/**
 * 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 {number[]}
 */
var findMode = function(root) {
    let ans = []
    let max = 0
    let count = 1
    let pre = null
    function fn(node){
        if(!node) return
        fn(node.left)
        if(pre){
            if(pre.val == node.val){
                count ++
            }else{
                if(count > max){
                    ans = [pre.val]
                    max = count
                }else if(count == max){
                    ans.push(pre.val)
                }
                count = 1
            }
        }
        pre = node
        fn(node.right)
    }
    fn(root)
    if(count > max){
        ans = [pre.val]
    }else if(count == max){
        ans.push(pre.val)
    }
    return ans
};
236. 二叉树的最近公共祖先

左右子树中一边有p,一边有q;或者当前节点是p或者q,自己孩子节点有q或者q

要从叶子节点不断向根节点寻找,只能使用携带返回值的回溯算法

递归函数返回值:

  • 如果当前节点等于p或者q,返回当前节点
  • 如果找到祖先节点,返回祖先节点

递归函数的逻辑:

  1. 如果当前节点等于p,或者q,或者null 返回该节点
  2. 递归左子树和右子树,得到返回值
  3. 如果左子树和右子树的返回值都不是null,表明一边有p,一边有q,则该节点就是需要寻找的最近祖先节点,将该节点作为返回值
  4. 如果左右子树只有一个返回值不是null,则将该返回值返回
  5. 如果左右子树的返回值都是null,则返回 null
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
var lowestCommonAncestor = function(root, p, q) {
    if(root == null || root == p ||root == q){
        return root
    }
    let left = lowestCommonAncestor(root.left, p, q)
    let right = lowestCommonAncestor(root.right, p, q)
    if(left && right) return root
    else if(!left && right) return right
    else if(!right && left) return left
    else return null
};
235. 二叉搜索树的最近公共祖先

在寻找公共祖先时利用好搜索二叉树的性质,如果当前节点处于[p,q]或者[q,p]区间内,则为最近公共祖先。

当节点值大于p,q的值,则继续在其左子树上搜索

当节点值小于p,q的值在其右子树上搜索

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */

/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
var lowestCommonAncestor = function(root, p, q) {
    if(!root) return null
    
    if(root.val > p.val && root.val > q.val){
        let left = lowestCommonAncestor(root.left, p, q)
        if(left) return left
    }else if(root.val < p.val && root.val < q.val){
        let right = lowestCommonAncestor(root.right, p, q)
        if(right) return right
    }
    return root
    
};
701. 二叉搜索树中的插入操作

遍历二叉搜索树,如果节点值小于插入元素,向右;如果节点值大于插入元素,向左,当遍历到空节点,则为插入元素的合适位置。

/**
 * 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
 * @param {number} val
 * @return {TreeNode}
 */
var insertIntoBST = function(root, val) {
    // 找到合适位置
    if(!root){
        let node = new TreeNode(val)
        return node
    }
    if(root.val < val){
        root.right = insertIntoBST(root.right, val)
    }else if(root.val > val){
        root.left = insertIntoBST(root.left, val)
    }
    return root
};
450. 删除二叉搜索树中的节点

像增加节点一样,使用递归函数的返回值来删除节点,删除节点的几种情况:

  • 没有找到删除节点:递归到空节点,返回 null
  • 找到删除节点:
    • 节点左右孩子都是空节点:直接删除该节点,返回null即可
    • 节点没有左孩子,有右孩子:返回节点右孩子
    • 节点有左孩子,没有右孩子:返回节点左孩子
    • 节点既有左孩子也有右孩子(比较难处理):将节点左孩子放到右孩子最左边节点的左孩子上,返回该节点的右孩子作为新节点
/**
 * 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
 * @param {number} key
 * @return {TreeNode}
 */
var deleteNode = function(root, key) {
    if(!root) return null
    if(root.val < key){
        root.right = deleteNode(root.right, key)
    }else if(root.val > key){
        root.left = deleteNode(root.left, key)
    }else{
        if(!root.left && !root.right) return null
        else if(!root.left && root.right) return root.right
        else if(!root.right && root.left) return root.left
        else{
            let p = root.right
            while(p.left){
                p = p.left
            }
            // console.log('右子树最左边的孩子:',p.val)
            p.left = root.left
            return root.right
        }
    }
    
    return root
};
669. 修剪二叉搜索树

如果当前节点为空节点,则直接返回 null

如果当前节点值小于下界low,则递归右子树,将递归右子树的结果替代当前节点作为返回值

如果当前节点值大于上界high,则递归左子树,将递归左子树的结果头戴当前节点作为返回值

如果当前节点在[low,high]中,当前节点符合条件,递归其左子树和右子树

/**
 * 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
 * @param {number} low
 * @param {number} high
 * @return {TreeNode}
 */
var trimBST = function(root, low, high) {
    if(!root) return null
    if(root.val < low){
        let right = trimBST(root.right, low, high)
        return right
    }else if(root.val > high){
        let left = trimBST(root.left, low, high)
        return left
    }
    root.left = trimBST(root.left, low, high)
    root.right = trimBST(root.right, low, high)
    return root
};
108. 将有序数组转换为二叉搜索树

和前面的构造最大二叉树类似,不断寻找切割点然后再递归左边和右边,不过这里的切割点就是中点,这样够构造的二叉树就是平衡二叉树。如果有偶数个元素的话切割点两个都可以。

/**
 * 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 {number[]} nums
 * @return {TreeNode}
 */
var sortedArrayToBST = function(nums) {
    if(!nums || nums.length == 0) return null
    let index = Math.floor(nums.length/2)
    let numsLeft = nums.slice(0,index)
    let numsRight = nums.slice(index+1)
    let node = new TreeNode(nums[index])
    node.left = sortedArrayToBST(numsLeft)
    node.right = sortedArrayToBST(numsRight)
    return node
};
538. 把二叉搜索树转换为累加树

要将大于自身的节点累加到当前节点上,所有需要先遍历右子树,然后需要一个指针表示前一个节点,将前一个节点的值累加到当前节点,再去遍历左子树。

/**
 * 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 convertBST = function(root) {
    let pre = null
    function fn(node){
        if(!node) return
        fn(node.right)
        if(pre){
            node.val = node.val + pre.val
        }
        pre = node
        fn(node.left)
    }
    fn(root)
    return root
};  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法营是一个优质的学习和讨论平台,提供了丰富的算法内容和讨论交流机会。在训营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题习。此外,训营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值