十、leetcode - 二叉树(JS)

388 阅读5分钟

144. 二叉树的前序遍历

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var preorderTraversal = function(root) {
    let res = [];
    const dfs = (root) => {
        if(!root) return;
        res.push(root.val);
        dfs(root.left);
        dfs(root.right);
    }
    dfs(root);
    return res;
};

94. 二叉树的中序遍历

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var inorderTraversal = function(root) {
    let res = [];
    const dfs = (root) => {
        if(!root) return;
        dfs(root.left);
        res.push(root.val);
        dfs(root.right);
    }
    dfs(root);
    return res;
};

145. 二叉树的后序遍历

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var postorderTraversal = function(root) {
    let res = [];
    const dfs = (root) => {
        if(!root) return;
        dfs(root.left);
        dfs(root.right);
        res.push(root.val);
    }
    dfs(root);
    return res;
};

剑指 Offer 07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。

假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

image.png

Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number[]} preorder
 * @param {number[]} inorder
 * @return {TreeNode}
 */
var buildTree = function(preorder, inorder) {
    if (!preorder.length || !inorder.length) {
        return null;
    }

    const rootVal = preorder[0];
    const node = new TreeNode(rootVal);

    let i = inorder.indexOf(rootVal);
    node.left = buildTree(preorder.slice(1, i + 1), inorder.slice(0, i));
    node.right = buildTree(preorder.slice(i + 1), inorder.slice(i + 1));
    return node;
};

102. 二叉树的层序遍历

即逐层地,从左到右访问所有节点

二叉树:[3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层序遍历结果:

[
  [3],
  [9,20],
  [15,7]
]
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
  if(!root) return [];
  let res = [];
  let queue = [];
  queue.push(root);
  while(queue.length) {
      let len = queue.length;
      let cur = [];
      while(len--) {
          let temp = queue.shift();
          cur.push(temp.val);
          if(temp.left) queue.push(temp.left);
          if(temp.right) queue.push(temp.right);
      }
      res.push(cur);
  } 
  return res;
}

103. 二叉树的锯齿形层序遍历

即先从左往右,再从右往左进行下一层遍历

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回锯齿形层序遍历如下:

[
  [3],
  [20,9],
  [15,7]
]
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var zigzagLevelOrder = function (root) {
    if(!root) return [];
    let res = [];
    let queue = [];
    queue.push(root);
    while(queue.length) {
        let len = queue.length;
        let cur = [];
        while(len--) {
            let temp = queue.shift();
            cur.push(temp.val);
            if(temp.left) queue.push(temp.left);
            if(temp.right) queue.push(temp.right);
        }
        res.length % 2 === 0 ? res.push(cur) : res.push(cur.reverse());
    }

    return res;
};

589. N 叉树的前序遍历

输入: root = [1,null,3,2,4,null,5,6]
输出: [1,3,5,6,2,4]
/**
 * // Definition for a Node.
 * function Node(val,children) {
 *    this.val = val;
 *    this.children = children;
 * };
 */
 
/**
 * @param {Node|null} root
 * @return {number[]}
 */
var preorder = function(root) {
    let res = [];
    const dfs = (root) => {
        if(!root) return;
        res.push(root.val);
        for(let i = 0; i < root.children.length; i++) {
            dfs(root.children[i]);
        }
    }
    dfs(root);
    return res;
};

590. N 叉树的后序遍历

输入: root = [1,null,3,2,4,null,5,6]
输出: [5,6,3,2,4,1]
/**
 * // Definition for a Node.
 * function Node(val,children) {
 *    this.val = val;
 *    this.children = children;
 * };
 */

/**
 * @param {Node|null} root
 * @return {number[]}
 */
var postorder = function(root) {
    let res = [];
    const dfs = (root) => {
        if(!root) return;
        for(let i = 0; i < root.children.length; i++) {
            dfs(root.children[i]);
        }
        res.push(root.val);
    }
    dfs(root);
    return res;
};

101. 对称二叉树

使用递归从上往下依次比较,并返回比较结果。

给定一个二叉树,检查它是否是镜像对称的。

二叉树 [1,2,2,3,4,4,3] 是对称的。
    1
   / \
  2   2
 / \ / \
3  4 4  3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
    1
   / \
  2   2
   \   \
   3    3
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isSymmetric = function(root) {
    if(!root) return true;
    const dfs = (left, right) => {
        if(!left && !right) return true;
        if(!left || !right || right.val !== left.val) return false;
        return dfs(left.left, right.right) && dfs(left.right, right.left);
    }
    return dfs(root.left, root.right);
};

226. 翻转二叉树

使用递归从上往下依次翻转,并返回翻转的结果。

输入:
     4
   /   \
  2     7
 / \   / \
1   3 6   9
输出:
     4
   /   \
  7     2
 / \   / \
9   6 3   1
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var invertTree = function(root) {
    const dfs = (root) => {
        if(!root) return root;
        let temp = root.left;
        root.left = root.right;
        root.right = temp;
        dfs(root.left);
        dfs(root.right);
        return root;
    }
    return dfs(root);
};

617. 合并二叉树

输入: 
	Tree 1                     Tree 2                  
          1                         2                             
         / \                       / \                            
        3   2                     1   3                        
       /                           \   \                      
      5                             4   7                  
输出: 
合并后的树:
	     3
	    / \
	   4   5
	  / \   \ 
	 5   4   7
/**
 * 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) {
    const dfs = (root1, root2) => {
        if(root1 === null && root2) return root2;
        if((root1 && root2 === null) || (root1 === null && root2 === null)) return root1;
        let root = new TreeNode(root1.val + root2.val);
        root.left = dfs(root1.left, root2.left);
        root.right = dfs(root1.right, root2.right);
        return root;
    }
    return dfs(root1, root2);
};

110. 平衡二叉树

平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

输入: root = [3,9,20,null,null,15,7]
输出: true
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isBalanced = function(root) {
    let res = true;
    const dfs = (root) => {
        if(!root) return 0;
        let left = dfs(root.left);
        let right = dfs(root.right);
        if(Math.abs(left - right) > 1) res = false;
        return Math.max(left, right) + 1;
    }
    dfs(root);
    return res;
};

104. 二叉树的最大深度

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

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

给定二叉树 [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
返回它的最大深度 3
/**
 * @param {TreeNode} root
 * @return {number}
 */
var maxDepth = function(root) {
    const dfs = (root) => {
        if(!root) return 0;
        return Math.max(dfs(root.left), dfs(root.right))+1;
    }
    return dfs(root);
};

111. 二叉树的最小深度

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

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

输入: root = [3,9,20,null,null,15,7]
输出: 2
/**
 * @param {TreeNode} root
 * @return {number}
 */
var minDepth = function(root) {
    const dfs = (root) => {
        if(!root) return 0;
        if(!root.left) return dfs(root.right) + 1;
        if(!root.right) return dfs(root.left) + 1;
        return Math.min(dfs(root.left), dfs(root.right)) + 1;
    }
    return dfs(root);
};

563. 二叉树的坡度

一个树的 节点的坡度 定义即为,该节点左子树的节点之和和右子树节点之和的 差的绝对值 。如果没有左子树的话,左子树的节点之和为 0 ;没有右子树的话也是一样。空结点的坡度是 0 。

整个树 的坡度就是其所有节点的坡度之和。

image.png

输入:root = [4,2,9,3,5,null,7]
输出:15
解释:
节点 3 的坡度:|0-0| = 0(没有子节点)
节点 5 的坡度:|0-0| = 0(没有子节点)
节点 7 的坡度:|0-0| = 0(没有子节点)
节点 2 的坡度:|3-5| = 2(左子树就是左子节点,所以和是 3 ;右子树就是右子节点,所以和是 5 )
节点 9 的坡度:|0-7| = 7(没有左子树,所以和是 0 ;右子树正好是右子节点,所以和是 7 )
节点 4 的坡度:|(3+5+2)-(9+7)| = |10-16| = 6(左子树值为 3、5 和 2 ,和是 10 ;右子树值为 9 和 7 ,和是 16 )
坡度总和:0 + 0 + 0 + 2 + 7 + 6 = 15
/**
 * @param {TreeNode} root
 * @return {number}
 */
var findTilt = function(root) {
    let res = 0;
    const dfs = (root) => {
        if(!root) return 0;
        let left = dfs(root.left);
        let right = dfs(root.right);
        res += Math.abs(left - right);
        return left + right + root.val;
    }
    dfs(root);
    return res;
};

98. 验证二叉搜索树

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。
输入: root = [2,1,3]
输出: true
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isValidBST = function (root) {
    const dfs = (root, min, max) => {
        if(!root) return true;
        if(root.val >= max || root.val <= min) return false;
        return dfs(root.left, min, root.val) && dfs(root.right, root.val, max);
    }
    return dfs(root, -Infinity, Infinity);
};

112. 路径总和

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

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

输入: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出: true
/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {boolean}
 */
var hasPathSum = function(root, targetSum) {
    let res = false;
    const dfs = (root, sum) => {
        if(res || !root) return;
        sum += root.val;
        if(!root.left && !root.right) {
            if(sum === targetSum) res = true;
            return;
        }
        if(root.left) dfs(root.left, sum);
        if(root.right) dfs(root.right, sum);
    }
    dfs(root, 0);
    return res;
};

113. 路径总和 II

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

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

image.png

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {number[][]}
 */
var pathSum = function(root, targetSum) {
    let res = [];
    const dfs = (root, sum, path) => {
        if(!root) {
            return;
        }
        sum += root.val;
        path.push(root.val);
        if(!root.left && !root.right) {
            if(sum === targetSum) res.push(path.slice());
        }
        if(root.left) dfs(root.left, sum, path);
        if(root.right) dfs(root.right, sum, path);
        path.pop();
    }
    dfs(root, 0, []);
    return res;
};