前端算法面试必刷题系列[46]

268 阅读5分钟

这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。

85. 平衡二叉树 (balanced-binary-tree)

标签

  • 平衡二叉树
  • 简单

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点左右两个子树高度差绝对值不超过 1

示例1:

image.png

输入:root = [3,9,20,null,null,15,7]
输出:true

image.png

输入:root = [1,2,2,3,3,null,null,4,4]
输出:false

基本思路

平衡二叉树,根据定义我们知道

  • 每个节点的左右子树高度(深度)差 不超过 1
  1. 我们实现一个求二叉树深度的函数

    • 当节点为空时返回 0
    • 要不选其左右子树更深的一条路深度 + 1 (为什么你画个图就明白了,非常简单,叶子节点左右子树都是 null,深度是 + 1,然后往上看)
  2. 递归去判断是否是平衡二叉树

    • root === null 是递归出口
    • 左右子树深度差小于1
    • 递归判断左右子树是否都平衡即可

写法实现

var isBalanced = function(root) {
  if (root === null) {
    return true
  }
  // 左右子树深度差小于1,以及左右子树都为平衡二叉,条件才会成立
  return Math.abs(depth(root.left) - depth(root.right)) <= 1 
    && isBalanced(root.left) 
    && isBalanced(root.right)
};

// 这个就是求二叉树深度函数
function depth(root) {
  if (root === null) {
      return 0
    }
  return Math.max(depth(root.left), depth(root.right)) + 1
}

86. 二叉树的最小深度 (convert-sorted-list-to-binary-search-tree)

标签

  • 二叉树
  • 简单

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定一个二叉树,找出其最小深度

最小深度是从根节点到[最近]叶子节点最短路径上的节点数量

说明:叶子节点是指没有子节点的节点。

示例 1: image.png

输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:

输入:root = [2,null,3,null,4,null,5,null,6]
输出:5

基本思路

其实这题还是明确最小深度从何而来。他其实是要求从根到最近叶子的最短路径,那么我们要递归求出根节点到叶子节点的深度输出最小值即可

基本步骤

其实深度问题搞清楚这两点

  1. 你是要分左右子树情况
  2. 别忘了你递归求出来的是不包含 root 的深度,要 + 1

写法实现

var minDepth = function(root) {
  if (root === null) {
    return 0
  }
  // 如果该节点的左右子树为空的话,深度就是另外一边的最小深度 + 1(root)
  if (root.left === null) {
    return minDepth(root.right) + 1
  }
  if (root.right === null) {
    return minDepth(root.left) + 1
  }
  // 然后递归取最小值
  return Math.min(minDepth(root.left), minDepth(root.right)) + 1
};

87. 路径总和 (path-sum)

标签

  • 二叉树
  • 简单

题目

leetcode 传送门

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点路径,这条路径上所有节点值相加等于目标和 targetSum

叶子节点 是指没有子节点的节点。

示例1:

image.png

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true

示例2: image.png

输入:root = [1,2,3], targetSum = 5
输出:false

基本思路

我们每遍历到一个节点,那么我们把他看成当前节点。 假定从根节点到当前节点的值之和val,我们可以将这个大问题转化为一个小问题: 是否存在从当前节点的子节点到叶子的路径,满足其路径和为 sum - val

递归最简单的思路就是抓住最小子问题,然后找到递归出口,就收了。千万不要钻进递归细节里。

或者本题用 dfs 也可求解,因为二叉树,就左右两分支,所以大多问题先想递归。

写法实现

var hasPathSum = function(root, targetSum) {
  // 这题还是递归,注意第二个参数是目标和
  if (root === null) {
    return false
  }
  // 递归出口,当这个节点是叶子节点,都减到最后了判断相等就行
  if (root.left === null && root.right === null) {
    return root.val === targetSum
  }
  // 递归,每经过一个节点,就用当前和减去该节点的值,继续往下递归
  return hasPathSum(root.left, targetSum - root.val) 
  || hasPathSum(root.right, targetSum - root.val)
};

88. 路径总和 II (path-sum-ii)

标签

  • 二叉树
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和路径

叶子节点 是指没有子节点的节点。

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例 2:

输入:root = [1,2,3], targetSum = 5
输出:[]

基本思路

DFS 不了解的同学可以看这 DFS 简介。

我们还是写一个 dfs 函数,思考为什么不用回溯了,我们要走到错误的路径上怎么办? 哈哈,多思考再看下面

原因是其实我们已经遍历了所有情况,二叉树就是左右,我们两条都试过了。

所以这题还没我们以前做的 DFS + 回溯难 对吧。

写法实现

var pathSum = function(root, targetSum) {
  if (root === null) {
    return []
  }
  let res = []
  const dfs = (root, curPath, curSum) => {
    // 当前和先加上当前节点值
    curSum = curSum + root.val
    // 当前路径也加入 Path
    curPath.push(root.val)
    // 加上当前值后 成功找到路径了 推进结果数组 (递归出口) 注意还要是叶子节点
    if (curSum === targetSum && !root.left && !root.right) {
      res.push(curPath)
    } else {
      // 如果还没找到,继续往其左右子树递归 加和(不是 null 的话)
      if (root.left !== null) {
        dfs(root.left, curPath.slice(), curSum)
      }
      if (root.right !== null) {
        dfs(root.right, curPath.slice(), curSum)
      }
    }
  }
  dfs(root, [], 0)
  return res
};

另外向大家着重推荐下这位大哥的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

参考