前端算法必刷题系列[89]

210 阅读4分钟

这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

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

好久没做关于树的题目,来两道

162. 二叉树的直径 (diameter-of-binary-tree)

标签

  • 简单
  • 递归

题目

leetcode 传送门

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

示例 1

给定二叉树

          1
         / \
        2   3
       / \     
      4   5    
      
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]

两结点之间的路径长度是以它们之间边的数目表示。

基本思路

二叉树的题,关键是理解题意,然后思考问题的答案能用数的一些基本特性来转化吗,然后基本都能用递归来解决,比如本题,要求任意两个结点路径长度中的最大值,其实我们就可以转化为 左右子树的最大深度和,然后加根节点的 1

  • 递归函数就是,求该节点为根时的最大直径, 最后把 root 传进去就是我们需要的答案

写法实现

var diameterOfBinaryTree = function(root) {
  let res = 0
  const dfs = (node) => {
    // 如果 node === null
    if (!node) return 0
    // 求左右子树的最大深度
    let left = dfs(node.left)
    let right = dfs(node.right)
    // 最大值跟当前最大比
    res = Math.max(left + right, res)
    // 返回以 node 为根的最大长度 + 1 是加根节点
    return Math.max(left, right) + 1
  }
  dfs(root)
  return res
};

简单题,就是不要想的太复杂,就是两边深度相加,就是最大长度,就想象上面例子从 5(左子树) 走到 3(右子树) 你能看出最大长度就是 左右深度相加就行。

163. 把二叉搜索树转换为累加树 (convert-bst-to-greater-tree)

标签

  • 中等
  • BST

题目

leetcode 传送门

给出二叉搜索树根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

  • 节点的左子树仅包含键 小于 节点键的节点。
  • 节点的右子树仅包含键 大于 节点键的节点。
  • 左右子树也必须是二叉搜索树。

示例 1

image.png

输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

示例 2

输入:root = [0,null,1]
输出:[1,null,1]

示例 3

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

示例 4

输入:root = [3,2,4,1]
输出:[7,9,4,10]

基本思路

首先我们需要知道 BST 的一些性质, 根据题意知道:

  • 二叉搜索树的中序遍历,访问的节点值递增的。
  • 所以这题跟中序遍历相关,能写出中序遍历模板不? 看我的这篇 一文说透二叉树遍历 注意代码中红字
// 递归方式的中序遍历
const midOrderTraversalRecursion = (root) => {
  let resList = []
  const midOrderTraversal = (node) => {
    if(node !== null) {
      // 先遍历左子树
      midOrderTraversal(node.left)           // ---------> (左)
      // 然后访问根节点 
      `!!!!! (这里你可以做点啥)`
      resList.push(node.val)                 // ---------> (根)
      // 再遍历右子树
      midOrderTraversal(node.right)          // ---------> (右)
    }
  }
  midOrderTraversal(root)
  return resList
}

本题是累加和,其实就是改造中序遍历拉,而且注意我们这题需要 反向的中序遍历, 所以需要改造模板,但思路基本相通的。

  • 对于每一个节点,先递归它的右子树
  • 再在当前节点做点什么, 累加上当前节点值,并更新当前节点值
  • 再递归它的左子树

写法实现

var convertBST = function(root) {
  let sum = 0
  let reverseinOrder = (node) => {
    if (node) {
      // 先遍历右子树
      reverseinOrder(node.right)

      // 中间做累加,更新
      sum = sum + node.val
      node.val = sum

      // 再递归左子树
      reverseinOrder(node.left)
    }
  } 
  reverseinOrder(root)
  return root
};

我认为思路还算清晰了,如果有不明白欢迎留言。

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

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

参考