leetcode刷题之有关树的算法

news/2024/7/19 15:34:04 标签: 算法, leetcode, js

144.二叉树的前序遍历

方法一:递归

var preorderTraversal = function(root) {
    let arr = []
    const preorder = root =>{
        //递归的出口
        if(root==null){
            return
        }
        arr.push(root.val)
        preorder(root.left)
        preorder(root.right)
    }
    preorder(root)
    return arr
};

方法二:迭代 使用栈

/**
 * 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 preorderTraversal = function(root) {
    if(!root) return []
    let arr = []
    let stack = [root]
    while(stack.length){
        let node = stack.pop()
        arr.push(node.val)
        node.right&&stack.push(node.right)
        node.left&&stack.push(node.left)
    }
    return arr
};

94.二叉树的中序遍历

方法一:递归

var inorderTraversal = function(root) {
    //递归 
    let arr = []
    const inorder = root =>{
        if(!root) return []
        inorder(root.left)
        arr.push(root.val)
        inorder(root.right)
    }
    inorder(root)
    return arr
};

方法二:迭代

var inorderTraversal = function(root) {
    //迭代
    let arr = []
    let stack = []
    //也就是 root == null
    if(!root) return []
    //左节点一直入栈
    while(root){
        stack.push(root)
        root = root.left
    }
    //开始出栈
    while(stack.length){
        let node = stack.pop()
        arr.push(node.val)
        let temp = node.right
        //当前的结点出栈之后,检查其右侧结点的情况 依次入栈
        while(temp){
            stack.push(temp)
            temp = temp.left
        }
    }
    return arr
};

145.二叉树的后序遍历

方法一:递归

var postorderTraversal = function(root) {
    //递归
    let arr = []
    const postorder = root =>{
        //递归出去的条件
        if(!root) return 
        postorder(root.left)
        postorder(root.right)
        arr.push(root.val)
    }
    postorder(root)
    return arr
};

方法二:迭代 使用栈

var postorderTraversal = function(root) {
    //先将root的值放入到arr中,然后将root.right left 最终得到的结果与后序遍历的结果正好相反
    let arr = []
    let stack = [root]
    if(!root) return []
    while(stack.length){
        let node = stack.pop()
        arr.push(node.val)
        node.left&&stack.push(node.left)
        node.right&&stack.push(node.right)
    }
    return arr.reverse()
};

102.二叉树的层序遍历

方法一:递归

var levelOrder = function(root) {
    //递归实现
    let arr = []
    const level = (root,i) =>{
        if(!root) return
        level(root.left,i+1)
        // arr[i] = arr[i]?arr[i].push(root.val):[root.val]
        arr[i]?arr[i].push(root.val):arr[i] = [root.val]
        level(root.right,i+1)
    }
    level(root,0)
    return arr
};

方法二:迭代 使用队列

/**
 * @param {TreeNode} root
 * @return {number[][]}
 层序遍历相当于广度优先遍历 需要借助一个队列   
 */
var levelOrder = function(root) {
    //使用队列
    let arr = []
    let queue = [root]
    let i = 0
    if(!root) return []
    while(queue.length){
        //记录当前队列的长度
        let len = queue.length
        //用来存储当前层结点
        let tempArr = []
        for(let i=0;i<len;i++){
            //出队
            let node = queue.shift()
            tempArr.push(node.val)
            node.left&&queue.push(node.left)
            node.right&&queue.push(node.right)
        }
        arr.push(tempArr)
    }
    return arr
};

617.合并二叉树

在这里插入图片描述

方法一:递归

当看不懂递归的时候,参考二叉树的递归执行过程

var mergeTrees = function(root1, root2) {
    //使用递归
    const merge = (root1,root2) =>{
        //递归跳出的条件
        if(root1==null){
            return root2
        }
        if(root2==null){
            return root1
        }
        //创建新的结点
        //递归的过程是 ①创建newNode 调用27行的递归 一直到左侧递归的最深层次,返回一个root 返回上一个递归函数(这个递归函数会继续执行28行递归,直到其right结点全都为空)  真的很复杂
        let newNode = new TreeNode(root1.val+root2.val)
        newNode.left = merge(root1.left,root2.left)
        newNode.right = merge(root1.right,root2.right)
        return newNode
    }
    return merge(root1,root2)
};

//这里直接修改root1
var mergeTrees = function(root1, root2) {
   //重新去写一遍
   const merge = (root1,root2) =>{
       //递归的出口
       if(root1==null){
           return root2
       }
       if(root2==null){
           return root1
       }
       //这里用的是前序遍历
       root1.val += root2.val
       root1.left = merge(root1.left,root2.left)
       root1.right = merge(root1.right,root2.right)
       //返回上一层递归
       return root1
   }
   return merge(root1,root2)
};

方法二:使用队列

var mergeTrees = function(root1, root2) {
   //root1 root2进入同一个栈
   if(root1==null) return root2
   if(root2==null) return root1
   let queue = []
   queue.push(root1)
   queue.push(root2)
   while(queue.length){
       let node1 = queue.shift()
       let node2 = queue.shift()
       node1.val += node2.val
       if(node1.left!==null&&node2.left!==null){
           queue.push(node1.left)
           queue.push(node2.left)
       }
       if(node1.left==null&&node2.left!==null){
           node1.left = node2.left
       }
       if(node1.right&&node2.right){
           queue.push(node1.right)
           queue.push(node2.right)
       }
       if(node1.right==null&&node2.right!==null){
           node1.right = node2.right
       }
   }
   return root1
};

226.翻转二叉树

在这里插入图片描述

方法一:递归

/**
 * @param {TreeNode} root
 * @return {TreeNode}
 整个树的交换过程中,会把真个node结点下面的所有的结点都会交换过来
 */
var invertTree = function(root) {
    //递归实现
    if(!root) return root
    const invert = root =>{
        //递归出去的条件
        if(root==null) return null
        //递归
        let temp = invert(root.left)
        root.left = invert(root.right)
        root.right = temp
        return root
    }
    return invert(root)
};

方法二:前序遍历过程中实现交换

/**
 * @param {TreeNode} root
 * @return {TreeNode}
 整个树的交换过程中,会把真个node结点下面的所有的结点都会交换过来
 */
var invertTree = function(root) {
    //前序遍历的过程中实现翻转
    if(root==null) return root
    if(root.left==null&&root.right==null) return root
    let stack = [root]
    while(stack.length){
        //出栈
        let node = stack.pop()
        //进行交换  如果node.left不存在 那么node.left=null
        let temp = node.left
        node.left = node.right
        node.right = temp
        //入栈
        node.left&&stack.push(node.left)
        node.right&&stack.push(node.right)
    }
    return root
};

方法三:层序遍历过程中实现交换

var invertTree = function(root) {
    //层序遍历过程中实现
    if(root==null) return root
    if(root.left==null&&root.right==null) return root
    let queue = [root]
    while(queue.length){
        //出队
        let node = queue.shift()
        //进行交换
        let temp = node.left
        node.left = node.right
        node.right = temp
        //入队
        node.left&&queue.push(node.left)
        node.right&&queue.push(node.right)

    }
    return root
};

101.对称二叉树

在这里插入图片描述

方法一:递归

var isSymmetric = function(root) {
    //同时进去两个节点 left and right
    const compare = (root1,root2) =>{
        if(root1==null&&root2==null){
            return true
        }else if(root1==null&&root2!==null || root1!==null&&root2==null){
            return false
        }else if(root1.val!==root2.val){
            return false
        }
        //递归持续下去的条件  左右都得满足
        let outside = compare(root1.left,root2.right)
        let inside  = compare(root1.right,root2.left)
        return outside&&inside
    }
    return compare(root.left,root.right)
};

方法二:使用队列

var isSymmetric = function(root) {
    //队列实现
    if(root==null){
        return true
    }else if(root.left==null&&root.right==null){
        return true
    }else if(root.left!==null&&root.right==null || root.left==null&&root.right!==null){
        return false
    }
    
    let queue = []
    queue.push(root.left)
    queue.push(root.right)
    while(queue.length){
        let node1 = queue.shift()
        let node2 = queue.shift()
        if(node1.val!==node2.val){
            return false
        }
        if(node1.left==null&&node2.right!==null || node1.left!==null&&node2.right==null){
            return false
        }
        if(node1.right==null&&node2.left!==null || node1.right!==null&&node2.left==null){
            return false
        }
        node1.left&&queue.push(node1.left)
        node2.right&&queue.push(node2.right)
        node1.right&&queue.push(node1.right)
        node2.left&&queue.push(node2.left)
    }
    return true
};


//或者
var isSymmetric = function(root) {
    //队列实现
    if(root==null){
        return true
    }
    //入队   先去入队 出队的时候再去判断是否为空
    let queue = []
    queue.push(root.left)
    queue.push(root.right)
    //如果root.left right都是空的话  就不会有下面的while循环 直接跳出去了
    while(queue.length){
        let leftNode = queue.shift()
        let rightNode = queue.shift()
        if(leftNode==null&&rightNode==null){
            //进入下一层循环
            continue
        }
        if(leftNode==null || rightNode==null || leftNode.val!==rightNode.val){
            return false
        }
        queue.push(leftNode.left)
        queue.push(rightNode.right)
        queue.push(leftNode.right)
        queue.push(rightNode.left)
    }
    return true
};

方法三:使用栈实现

var isSymmetric = function(root) {
    //栈实现
    let stack = []
    if(root==null){
        return true
    }
    stack.push(root.left)
    stack.push(root.right)
    while(stack.length){
        let leftNode = stack.pop()
        let rightNode = stack.pop()
        if(leftNode==null&&rightNode==null){
            //进入下一层循环
            continue
        }
        if(leftNode==null || rightNode==null || leftNode.val!==rightNode.val){
            return false
        }
        stack.push(leftNode.left)
        stack.push(rightNode.right)
        stack.push(leftNode.right)
        stack.push(rightNode.left)
    }
    return true
};

543.二叉树的直径

在这里插入图片描述

var diameterOfBinaryTree = function(root) {
  //二叉树的直径==根节点左右两侧高度之和的最大值
  let res = 0 //用来记录递归过程中遇到的和的最大值
  if(!root) return 0
  const diameter = root =>{
      if(root==null) return 0
      let leftHeight = diameter(root.left)
      let rightHeight = diameter(root.right)
      res = Math.max(res,(leftHeight+rightHeight))
      return Math.max(leftHeight,rightHeight)+1   //这是返回给上一层递归的结果值
  }
  diameter(root)
    return res
};

104.二叉树的最大深度

在这里插入图片描述

方法一:层序遍历之后,计算res的length

var maxDepth = function(root) {
   //方法一:层序遍历之后,将其放入到数组中,然后判断数组的长度
   let res = []
   if(root==null) return 0
   const level = (root,i) =>{
       if(root==null){
           return
       }
       //中序遍历的过程中进行压栈处理
       level(root.left,i+1)
       res[i]?res[i].push(root.val):res[i]=[root.val]
       level(root.right,i+1)
   }
   level(root,0)
   return res.length
};

//层序遍历过程中 不进行压栈处理
var maxDepth = function(root) {
   //层序遍历的过程中动态记录最大的深度
   let max = 0
   if(root==null) return 0
   const level = (root,i)=>{
       if(root==null){
           return
       }
       level(root.left,i+1)
       max = Math.max(max,i)
       level(root.right,i+1)
   }
   level(root,0)
   return max+1
};

方法二:同二叉树最大直径的求解过程

var maxDepth = function(root) {
   //利用二叉树最大直径的处理过程中 类似
   const maxit = root =>{
       if(root==null) return 0
       let leftHeight = maxit(root.left)
       let rightHeight = maxit(root.right)
       return Math.max(leftHeight,rightHeight) +1
   }
   return maxit(root) 
};

方法三:使用队列

var maxDepth = function(root) {
   //使用队列
   if(root==null) return 0
   let queue = [root]
   let arr = []
   while(queue.length){
       let len = queue.length
       let temp = []
       for(let i=0;i<len;i++){
           let node = queue.shift()
           temp.push(node.val)    
           node.left&&queue.push(node.left)
           node.right&&queue.push(node.right)
       }
       arr.push(temp)
   }
   return arr.length
};



//优化
var maxDepth = function(root) {
   //使用队列
   if(root==null) return 0
   let queue = [root]
   let max = 0
   while(queue.length){
       let len = queue.length
       for(let i=0;i<len;i++){
           let node = queue.shift()    
           node.left&&queue.push(node.left)
           node.right&&queue.push(node.right)

       }
       max++
   }
   return max
};

http://www.niftyadmin.cn/n/285340.html

相关文章

【学习笔记】斯特林反演+单位根反演

这东西 quack \text{quack} quack教我的。显然完全不在我的技能树上。 所以就抄了一下 ppt \text{ppt} ppt。其实我完全不会好吧。 有很多 nb \text{nb} nb的推式子过程。但是我可能只会把部分结论呈现出来。 1.1 1.1 1.1 斯特林反演 g ( n ) ∑ i 0 n { n i } f ( i ) ⇒ …

Spring框架的拦截器(Interceptor)

SpringMVC的拦截器 与 JavaServlet的过滤器 类似&#xff0c;它主要用于拦截用户的请求并做相应的处理&#xff0c;通常应用于权限认证&#xff08;保护服务器资源 &#xff09;、记录请求信息的日志、判断用户是否登录等功能。 自定义登录拦截器 一、创建一个类并实现Handler…

linux驱动开发 - 09_中断

文章目录 1 Linux 中断简介1.1 Linux 中断 API 函数1、中断号2、 request_irq 函数3、free_irq 函数4、中断处理函数5、中断使能与禁止函数 1.2 上半部与下半部1、软中断2、tasklet3、工作队列 1.3 设备树中断信息节点1.4 获取中断号 2 程序编写2.1 修改设备树文件2.2 按键中断…

[Data structure]单链表常见算法题

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;数据结构。数据结构专栏主要是在讲解原理的基础上拿Java实现 ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一…

【LeetCode】646. 最长数对链

646. 最长数对链&#xff08;中等&#xff09; 思路 这道题和 300. 最长递增子序列 类似&#xff0c;我们可以定义 dp 数组&#xff0c;其中 dp[i] 表示以 i 结尾的子序列的性质。在处理好每个位置后&#xff0c;统计一遍各个位置的结果即可得到题目要求的结果。 但是题目中强…

Ortools的几种解类型

网上资料有点少&#xff0c;不定期更新项目中遇到的Ortools的有关资料 状态说明OPTIMAL已找到最佳可行解决方案。FEASIBLE找到了可行的解决方案&#xff0c;但我们不知道它是否最优。INFEASIBLE事实证明无法解决问题。MODEL_INVALID给定的 CpModelProto 未通过验证步骤。您可以…

Cadence基础操作:ADE L仿真基础操作

仿真器启动 schematic视图左上角 launch 启动各种仿真器&#xff0c;ADE L界面左上角Launch 启动ADL XL 和ADE GXL。通过ADE L启动的ADEXL 会继承ADE L的各种设置&#xff0c;如变量、plot and save的点等等。 仿真器主要设置 1.仿真器选择&#xff1a;如图&#xff0c;Setup里…

【游戏逆向】Lua游戏逆向及破解方法介绍

前言 随着手游的发展&#xff0c;越来越多的Cocos-lua端游开发者转移到手游平台。Lua脚本编写逻辑的手游也是越来越多&#xff0c;如梦幻西游、刀塔传奇、开心消消乐、游龙英雄、奇迹暖暖、疾风猎人、万万没想到等手游。随着Lua手游的增加&#xff0c;其安全性更值得关注&…