树形结构-对应算法详解二

416 阅读6分钟

文章简要概述

  • 本文主要进行树相关的算法题刷题题解记录,记录树相关算法以及如何解。
  • 这文一共有5道题,主要介绍leetcode中968. 监控二叉树662. 二叉树最大宽度144. 二叉树的前序遍历589. N 叉树的前序遍历、和226. 翻转二叉树的解题思路。

与树相关算法

968. 监控二叉树

968. 监控二叉树--leetcode

题目大意:

给定一个二叉树,我们在树的节点上安装摄像头。

节点上的每个摄影头都可以监视**其父对象、自身及其直接子对象。**

计算监控树的所有节点所需的最小摄像头数量。

示例

bst_cameras_01.png

输入: [0,0,null,0,0]

输出: 1

解释: 如图所示,一台摄像头足以监控所有节点。

解题思路:

  • 如果在 root 处安放摄像头,则root的left,right 一定也会被监控到。此时,只需要保证left 的两棵子树被覆盖,同时保证 right 的两棵子树也被覆盖即可。
  • 如果 root 处不安放摄像头,则除了覆盖 root 的两棵子树之外,孩子left,right 之一必须要安装摄像头,从而保证 root 会被监控到。 那么可以得到一下结论:
  • 状态 a:root 必须放置摄像头的情况下,覆盖整棵树需要的摄像头数目。
  • 状态 b:覆盖整棵树需要的摄像头数目,无论 root 是否放置摄像头。
  • 状态 c:覆盖两棵子树需要的摄像头数目,无论节点 root 本身是否被监控到。

1641992766103.jpg

企业微信截图_75f86465-9064-4b73-a69b-716097a3b09a.png

代码:

function minCameraCover (root) {
  const dfs = (root) => {
        if (!root) {
            return [Math.floor(Number.MAX_SAFE_INTEGER / 2), 0, 0];
        }
        const [la, lb, lc] = dfs(root.left);
        const [ra, rb, rc] = dfs(root.right);
        const a = lc + rc + 1;
        const b = Math.min(a, Math.min(la + rb, ra + lb));
        const c = Math.min(a, lb + rb);
        return [a, b, c];
    }

    return dfs(root)[1];
};

662. 二叉树最大宽度

662. 二叉树最大宽度--leetcode

题目大意:

给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。

每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。

示例:

输入:

       1
     /   \
    3     2
   / \     \  
  5   3     9 

输出: 4

解释: 最大值出现在树的第 3 层,宽度为 4 (5,3,null,9)。

解题思路:

  • 按照深度优先的顺序,我们记录每个节点的 position 。对于每一个深度,第一个到达的位置会被记录在 max[dep] 中。
  • 然后对于每一个节点,它对应这一层的可能宽度是 pos - max[dep] + 1
  • 将每一层这些可能的宽度去一个最大值就是答案。

代码:

/**
 * 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}
 */
function widthOfBinaryTree (root) {
   let max = [];
   function dsf(root, dep, idx) {
     if(!root) return;
     max[dep] = (max[dep] || [idx, idx]);
     max[dep][0] = Math.min(max[dep][0], idx)
     max[dep][1] = Math.max(max[dep][1], idx)
     dsf(root.left, dep + 1, (idx << 1) + 1);
     dsf(root.right, dep + 1, (idx << 1) + 2);
   }
   dsf(root, 0, 0);
   return max.reduce((max, [l, r]) => Math.max(max, r - l), 0) + 1;
};

144. 二叉树的前序遍历

144. 二叉树的前序遍历--leetcode

题目大意:

给你二叉树的根节点 `root` ,返回它节点值的 **前序** **遍历。

示例:

inorder_1.jpeg

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

输出: [1,2,3]

解题思路:

  • 按照根左右的顺序,递归即可。

代码:

/**
 * 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[]}
 */
 function preorder (root, arr) {
   if (!root) return root;
   arr.push(root.val);
   preorder(root.left, arr);
   preorder(root.right, arr);
 }
var preorderTraversal = function(root) {
   const arr = [];
   preorder(root, arr);
   return arr;
};

589. N 叉树的前序遍历

589. N 叉树的前序遍历--leetcode

题目大意:

给定一个 N 叉树,返回其节点值的 前序遍历 。

N 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。

进阶:

递归法很简单,你可以使用迭代法完成此题吗?

示例:

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

输出: [1,3,5,6,2,4]

解题思路:

  • 采用栈的方式,将每一层的值放入栈中,为了保持从左到右的顺序,我们对应每一层的children的值先反转顺序。 -然后从栈顶取元素,这样递归操作。

代码:

/**
 * // Definition for a Node.
 * function Node(val, children) {
 *    this.val = val;
 *    this.children = children;
 * };
 */

/**
 * @param {Node|null} root
 * @return {number[]}
 */
function preorder (root) {
    if (!root) return [];
    const res = [];
    const cur = [];
    cur.push(root);
    while(cur.length) {
        const node = cur.pop();
        res.push(node.val);
        node.children.reverse();
        for(k in node.children) {
            cur.push(node.children[k])
        }
    }
    return res;
};

226. 翻转二叉树

226. 翻转二叉树--leetcode

题目大意:

翻转一棵二叉树。

示例:

输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

输出:

     4
   /   \
  7     2
 / \   / \
9   6 3   1

解题思路:

  • 获取当前节点的左右子节点的内容,将左右子节的内容先反转
  • 然后将反转后的左右子节点与根节点的左右子节点进行交换
  • 递归以上操作

代码:

/**
 * 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 invertTree = function(root) {
   if (!root) return null;
   const left = invertTree(root.left);
   const right = invertTree(root.right);
   root.left = right;
   root.right = left;
   return root;
};

结束语

数据结构与算法相关的练习题会持续输出,一起来学习,持续关注。当前是树部分。后期还会有其他类型的数据结构,题目来源于leetcode。

往期文章:

树形结构-对应算法详解一                             链表相关算法复习一                             链表相关算法复习二

链表相关算法复习三                                      数据结构与算法-栈一                           数据结构与算法-栈二

数据结构与算法-队列一                                数据结构与算法-队列二                       数据结构与算法-链表一

数据结构与算法-链表二                               数据结构与算法-链表三

有兴趣的可以一起来刷题,如果文章对你有帮助,感谢点赞👍,关注!