数据结构与算法leetcode题目解析-----树(持续更新)

1,948 阅读18分钟

(声明:所有题目都是leetcode上非会员题目)

树的定义

在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

  1. 每个节点都只有有限个子节点或无子节点;
  2. 没有父节点的节点称为根节点;
  3. 每一个非根节点有且只有一个父节点;
  4. 除了根节点外,每个子节点可以分为多个不相交的子树;
  5. 树里面没有环路(cycle)

二叉树

在计算机科学中,二叉树(英语:Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒。

一棵深度为k,且有2^k-1个结点的二叉树,称为满二叉树。这种树的特点是每一层上的结点数都是最大结点数。而在一棵二叉树中,除最后一层外,若其余层都是满的,并且或者最后一层是满的,或者是在右边缺少连续若干结点,则此二叉树为完全二叉树。具有n个结点的完全二叉树的深度为Math.floor(log2n)+1。深度为k的完全二叉树,至少有2k-1个叶子结点,至多有2k-1个结点。

与普通树不同,普通树的节点个数至少为1,而二叉树的节点个数可以为0;普通树节点的最大分支度没有限制,而二叉树节点的最大分支度为2;普通树的节点无左、右次序之分,而二叉树的节点有左、右次序之分。

二叉查找树

二叉查找树(英语:Binary Search Tree),也称为二叉搜索树、有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:

  1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;
  4. 没有键值相等的节点。

二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(logn)

中序遍历二叉查找树可得到一个节点值的有序序列,一个无序序列可以透过建构一棵二叉查找树变成一个有序序列,建构树的过程即为对无序序列进行查找的过程。每次插入的新的结点都是二叉查找树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。搜索、插入、删除的复杂度等于树高,p平均时间复杂度O(logn),最坏O(n)。

虽然二叉查找树的最坏效率是O(n),但它支持动态查询,且有很多改进版的二叉查找树可以使树高为O(logn),从而将最坏效率降至O(logn),如AVL树、红黑树等

本文将不断收录自己在解决leetcode上算法问题时,遇到的和树这种数据结构相关的问题

树相关问题技巧

  1. 层序遍历过程中,用index来维护节点索引,一个节点索引是index,那他的左孩子索引是index * 2,右孩子索引是index * 2 + 1
  2. 树形问题很多都可以用递归解决
  3. 树形问题总是涉及到BFS或者DFS过程

Leetcode上树相关的问题

leetcode 94, 144, 145. 二叉树的前中后序遍历

题目地址:二叉树的前序遍历 二叉树的中序遍历 二叉树的后序遍历

关于这三个二叉树最基本的问题,我在另一篇专栏里有详细给出解法,这里不再列出,可以参考 二叉树前中后序遍历非递归实现(JavaScript)

leetcode 98. 验证二叉搜索树

题目地址:验证二叉搜索树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
 var isValidBST = function(root, min = -Infinity, max = Infinity) {
    if (!root) return true;
    if (root.val <= min || root.val >= max) return false;
    return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max);
};

leetcode 100. 相同的树

题目地址:相同的树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {boolean}
 */
var isSameTree = function(p, q) {
    if (!p && !q) {
        return true
    }
    if ((!p && q) || (p && !q)) {
        return false
    }
    if (p && q) {
        if (p.val === q.val) {          
            return isSameTree(p.left, q.left) && isSameTree(p.right, q.right)
        } else {
            return false
        }
    }
};

leetcode 101. 对称二叉树

题目地址:对称二叉树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isSymmetric = function(root) {
    function isMirror (node1, node2) {
        if (node1 == null && node2 == null) return true;
        if (node1 == null || node2 == null) return false;
        return (node1.val == node2.val) && isMirror(node1.right, node2.left) && isMirror(node1.left, node2.right)
    }
    return isMirror(root, root)
};

leetcode 102. 二叉树的层次遍历

题目地址:二叉树的层次遍历

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
    let res = []
    let queue = []
    if (root) {
        let level = 0
        queue.push({ node: root, level })
        while (queue.length) {
            const item = queue.shift()
            const node = item.node
            let level = item.level
            if (level === res.length) {
                res.push([])
            }
            res[level].push(node.val)
            node.left && queue.push({ node: node.left, level: level + 1 })
            node.right && queue.push({ node: node.right, level: level + 1 })
        }
    }
    return res
};

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

题目地址:二叉树的锯齿形层次遍历

BFS,level维护层级

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var zigzagLevelOrder = function(root) {
    const res = []
    if (root) {
        const queue = [root]
        let level = 0
        while (queue.length) {
            const len = queue.length
            const arr = []
            if (level % 2) {
                for (let i = 0; i < len; i++) {
                    const node = queue.shift()
                    node.left && queue.push(node.left)
                    node.right && queue.push(node.right)
                    arr.unshift(node.val)
                }
            } else {
                for (let i = 0; i < len; i++) {
                    const node = queue.shift()
                    node.left && queue.push(node.left)
                    node.right && queue.push(node.right)
                    arr.push(node.val)
                }
            }
            res.push(arr)
            level ++
        }
    }
    return res
};

leetcode 104. 二叉树的最大深度

题目地址:二叉树的最大深度

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
 var maxDepth = function(root) {
    if (root === null) {
        return 0
    }
    return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1
};

leetcode 105. 从前序与中序遍历序列构造二叉树

题目地址:从前序与中序遍历序列构造二叉树

/**
 * 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 root = new TreeNode(preorder[0])
    const index = inorder.indexOf(root.val);
    // 递归找到每个节点
    root.left = buildTree(preorder.slice(1,index+1),inorder.slice(0,index))
    root.right = buildTree(preorder.slice(index+1), inorder.slice(index + 1))
    return root
};

leetcode 106. 从中序与后序遍历序列构造二叉树

题目地址:从中序与后序遍历序列构造二叉树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number[]} inorder
 * @param {number[]} postorder
 * @return {TreeNode}
 */
var buildTree = function(inorder, postorder) {
    if (!inorder.length || !postorder.length) {
        return null
    }
    const root = new TreeNode(postorder[postorder.length - 1])
    const i = inorder.indexOf(root.val)
    root.left = buildTree(inorder.slice(0, i), postorder.slice(0, i))
    root.right = buildTree(inorder.slice(i + 1), postorder.slice(i, postorder.length - 1))
    return root
};

leetcode 107. 二叉树的层次遍历 II

题目地址:二叉树的层次遍历II

解法一:DFS

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrderBottom = function(root) {
    let res = []
    let queue = []
    if (root) {
        let level = 0
        queue.push({ node: root, level })
        while (queue.length) {
            const item = queue.shift()
            const node = item.node
            const level = item.level
            if (level === res.length) {
                res.unshift([])
            }
            res[0].push(node.val)
            node.left && queue.push({ node: node.left, level: level + 1 })
            node.right && queue.push({ node: node.right, level: level + 1 })
        }
    }
    return res
};

解法二:BFS

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrderBottom = function(root) {
    const res = []
    if (root) {
        const queue = [root]
        while (queue.length) {
            const len = queue.length
            const temp = []
            for (let i = 0; i < len; i++) {
                const node = queue.shift()
                temp.push(node.val)
                node.left && queue.push(node.left)
                node.right && queue.push(node.right)
            }
            res.unshift(temp)
        }
    }
    return res
};

leetcode 108. 将有序数组转换为二叉搜索树

题目地址:将有序数组转换为二叉搜索树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number[]} nums
 * @return {TreeNode}
 */
var sortedArrayToBST = function (nums) {
  if (nums.length == 0) return null;
  let cen = Math.floor(nums.length / 2)
  let node = new TreeNode(nums[cen])
  node.left = sortedArrayToBST(nums.slice(0, cen))
  node.right = sortedArrayToBST(nums.slice(cen + 1))
  return node;
};

leetcode 110. 平衡二叉树

题目地址:平衡二叉树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
 var isBalanced = function(root) {
    // 遍历到底还没有发现高度差超过 1 的左右子树,那么这个子树肯定符合平衡二叉树的规范
    if (!root) {
        return true
    }
    // 判断左右子树的高度差,如果超过 1 那么立即返回 false
    if (Math.abs(getHeight(root.left) - getHeight(root.right)) > 1) {
        return false
    }
    // 分别递归左右子树
    return isBalanced(root.left) && isBalanced(root.right)
    // 获取某个子树的高度
    function getHeight (root) {
        if (!root) {
            return 0
        }
        return Math.max(getHeight(root.left), getHeight(root.right)) + 1
    }
};

leetcode 111. 二叉树的最小深度

题目地址:二叉树的最小深度

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var minDepth = function(root) {
    if (!root) {
        return 0
    }
    if (root.left === null && root.right === null) {
        return 1
    }
    if (root.left && !root.right) {
        return minDepth(root.left) + 1
    }
    if (!root.left && root.right) {
        return minDepth(root.right) + 1
    }
    return Math.min(minDepth(root.left), minDepth(root.right)) + 1
};

leetcode 112. 路径总和

题目地址:路径总和

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} sum
 * @return {boolean}
 */
var hasPathSum = function(root, sum) {
    if (!root) {
        return false
    }
    if (!root.left && !root.right) {
        return root.val === sum
    }
    return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val)
};

leetcode 113. 路径总和 II

题目地址:路径总和 II

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} sum
 * @return {number[][]}
 */
var pathSum = function(root, sum) {
    const result = []
    const digui = function(node, route, localSum){
        if(!node) return
        route.push(node.val)
        if(!node.left && !node.right && node.val + localSum === sum){
            result.push(route.slice())
        }else{
            if(node.left) digui(node.left, route.slice(), localSum + node.val)
            if(node.right) digui(node.right, route.slice(), localSum + node.val)
        }
    }
    digui(root, [], 0)
    return result
};

leetcode 114. 二叉树展开为链表

题目地址:二叉树展开为链表

解法一:先序遍历

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {void} Do not return anything, modify root in-place instead.
 */
var flatten = function (root) {
    if (!root) {
        return null
    }
    let temp = new TreeNode(null)
    temp.right = root
    const stack = [root]
    let prev = temp
    while (stack.length > 0) {
        root = stack.pop()
        prev.right = root
        prev.left = null
        root.right && stack.push(root.right)
        root.left && stack.push(root.left)
        prev = root
    }
    return temp.right
}

解法二:

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {void} Do not return anything, modify root in-place instead.
 */
var flatten = function (root) {
    let node = root
    while (node) {
        if (node.left) {
            // 找到当前节点左节点的最右子节点
            let temp = node.left
            while (temp.right) {
                temp = temp.right
            }
            // 最右子节点的有节点指向为当前节点右节点
            temp.right = node.right
            // 把当前节点右节点指向左节点
            node.right = node.left
            // 左节点为空
            node.left = null
        }
        node = node.right
    }
    return root
}

leetcode 129. 求根到叶子节点数字之和

题目地址:求根到叶子节点数字之和

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var sumNumbers = function(root) {
    var binaryTreePaths = function(root) {
        const res = []
        if (!root) {
            return res
        }
        if (!root.left && !root.right ) {
            res.push(root.val.toString())
            return res
        }
        const leftPath = binaryTreePaths(root.left)
        for (let i = 0; i < leftPath.length; i++) {
            res.push(root.val.toString() + leftPath[i])
        }
        const rightPath = binaryTreePaths(root.right)
        for (let i = 0; i < rightPath.length; i++) {
            res.push(root.val.toString() + rightPath[i])
        }
        return res
    };
    const arr = binaryTreePaths(root)
    let sum = 0
    if (arr .length) {
        arr.forEach(item => {
            sum += parseInt(item)
        })
    }
    return sum
};

leetcode 173. 二叉搜索树迭代器

题目地址:二叉搜索树迭代器

/**
* Definition for a binary tree node.
* function TreeNode(val) {
*     this.val = val;
*     this.left = this.right = null;
* }
*/
const inorderTraversal = function(root) {
    const res = [], stack = []
    let node = root;
    while (stack.length > 0 || node !== null) {
        // 这里用当前节点node是否存在,简化代码,
        if (node) {
            stack.push(node);
            node = node.left
        } else {
            node = stack.pop();
            res.push(node.val);
            node = node.right;
        }
    }
    return res;
};
/**
* @param {TreeNode} root
*/
var BSTIterator = function(root) {
    this.res = inorderTraversal(root)
    this.cur = 0
};

/**
* @return the next smallest number
* @return {number}
*/
BSTIterator.prototype.next = function() {
    const index = this.cur
    this.cur ++
    return this.res[index]
};

/**
* @return whether we have a next smallest number
* @return {boolean}
*/
BSTIterator.prototype.hasNext = function() {
    return this.cur < this.res.length
};

/** 
* Your BSTIterator object will be instantiated and called as such:
* var obj = new BSTIterator(root)
* var param_1 = obj.next()
* var param_2 = obj.hasNext()
*/

leetcode 199. 二叉树的右视图

题目地址:二叉树的右视图

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
// BFS
var rightSideView = function(root) {
    if (!root) {
        return []
    }
    const nums = [root]
    const res = []
    let right
    while (nums.length) {
        let len = nums.length
        for (let i = 0; i < len; i++) {
            let node = nums.shift()
            right = node.val
            node.left && nums.push(node.left)
            node.right && nums.push(node.right)
        }
        res.push(right)
    }
    return res
};

leetcode 222. 完全二叉树的节点个数

题目地址:完全二叉树的节点个数

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var countNodes = function(root) {
    if (!root) {
        return 0
    }
    let left_height = 0
    let left_node = root
    let right_height = 0
    let right_node = root
    while(left_node) {
        left_node = left_node.left
        left_height += 1
    }
    while (right_node) {
        right_node = right_node.right
        right_height += 1
    }
    if (left_height === right_height) {
        return Math.pow(2, left_height) - 1
    }
    return 1 + countNodes(root.left) + countNodes(root.right)
};

leetcode 226. 翻转二叉树

题目地址:翻转二叉树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var invertTree = function(root) {
    if (!root) {
        return null
    }
    [root.left, root.right] = [invertTree(root.right), invertTree(root.left)]
    return root
};

leetcode 230. 二叉搜索树中第K小的元素

题目地址:二叉搜索树中第K小的元素

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} k
 * @return {number}
 */
// 二叉搜索树中序遍历,得到的是从小到大排列
var kthSmallest = function(root, k) {
    let res = [];
    function lnr(node){
        if(node && res.length<k){
            lnr(node.left);
            res.push(node.val);
            lnr(node.right);
        }
    }
    lnr(root);  
    return res[k-1];
};

leetcode 235. 二叉搜索树的最近公共祖先

题目地址:二叉搜索树的最近公共祖先

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
var lowestCommonAncestor = function(root, p, q) {
   if (p.val < root.val && q.val < root.val) {
        return lowestCommonAncestor(root.left, p, q)
    } else if (p.val > root.val && q.val > root.val) {
        return lowestCommonAncestor(root.right, p, q)
    } else {
        return root
    }
};

leetcode 236. 二叉树的最近公共祖先

题目地址:二叉树的最近公共祖先

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
var lowestCommonAncestor = function(root, p, q) {
    if(root == null || root == p || root == q){
        return root;
    }
    let left = lowestCommonAncestor(root.left,p,q);
    let right = lowestCommonAncestor(root.right,p,q);
    // p,q在root的左右子树
    if(left != null && right != null){
        return root;
    }
    // 只找到一个说明,p,q之一就是最近公共结点,另一个是该节点子节点
    return left != null ? left : right;
};

leetcode 257. 二叉树的所有路径

题目地址:二叉树的所有路径

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {string[]}
 */
var binaryTreePaths = function(root) {
    const res = []
    if (!root) {
        return res
    }
    if (!root.left && !root.right ) {
        res.push(root.val.toString())
        return res
    }
    const leftPath = binaryTreePaths(root.left)
    for (let i = 0; i < leftPath.length; i++) {
        res.push(root.val.toString() + '->' + leftPath[i])
    }
    const rightPath = binaryTreePaths(root.right)
    for (let i = 0; i < rightPath.length; i++) {
        res.push(root.val.toString() + '->' + rightPath[i])
    }
    return res
};

leetcode 404. 左叶子之和

题目地址:左叶子之和

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var sumOfLeftLeaves = function(root) {
    if(!root) return 0;
    let sum = 0;
    let fn = (curNode) => {
        if(curNode.left && (!curNode.left.left && !curNode.left.right)){
            sum += curNode.left.val;
        }
        if(curNode.left){
            fn(curNode.left)
        }
        if(curNode.right){
            fn(curNode.right)
        }
    }
    fn(root)
    return sum;
};

leetcode 450. 删除二叉搜索树中的节点

题目地址:删除二叉搜索树中的节点

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} key
 * @return {TreeNode}
 */
var deleteNode = function(root, key) {
    if(root == null){
        return root;
    }
    if(key == root.val){
        // 如果该节点的左子树为空,返回该节点的右子树
        if(root.left == null){
            return root.right;
        } else if(root.right == null){
            return root.left;
        } else {
            let node = root.right;
            while(node.left != null){
                node = node.left;
            }
            node.left = root.left;
            return root.right;
        }
        // key 比root大,则从右子树中删除 key 节点
    } else if(key > root.val) {
        root.right = deleteNode(root.right,key);
    } else {
        root.left = deleteNode(root.left,key);
    }
    return root;
}

leetcode 501. 二叉搜索树中的众数

题目地址:二叉搜索树中的众数

中序遍历二叉搜索树,得到的数组是从小到大排序的,这个过程中进行众数统计

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
 var findMode = function(root) {
    let res = [], maxcount = 0, prev = null, count = 0
    function binarySearch (root) {
        if (!root) {
            return 
        }
        binarySearch(root.left)
        if (prev === root.val) {
            count ++
        } else {
            count = 1
        }
        if (maxcount === count) {
            res.push(root.val)
        } else if (maxcount < count) {
            res = [root.val]
            maxcount = count
        }
        prev = root.val
        binarySearch(root.right)
    }
    binarySearch(root)
    return res
};

leetcode 530. 二叉搜索树的最小绝对差

题目地址:二叉搜索树的最小绝对差

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var getMinimumDifference = function(root) {
    // 中序遍历,对于二叉搜索树就是从小到大排序(非递归)
    const res = [], stack = []
    let node = root;
    while (stack.length > 0 || node !== null) {
        // 这里用当前节点node是否存在,简化代码,
        if (node) {
            stack.push(node);
            node = node.left
        } else {
            node = stack.pop();
            res.push(node.val);
            node = node.right;
        }
    }
    const len = res.length
    let min = Infinity
    // 遍历,找到最小绝对差
    for (let i = 0; i < len - 1; i ++) {
        min = Math.min(min, Math.abs(res[i] - res[i + 1]))
    }
    return min
};

leetcode 543. 二叉树的直径

题目地址:二叉树的直径

这个问题本质是求一棵树左右子树的高度和

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var diameterOfBinaryTree = function(root) {
    let res = 0
    function getHeight (root) {
        if (!root) {
            return 0
        }
        // 左子树深度
        const left = root.left ? getHeight(root.left) + 1 : 0
        // 右子树深度
        const right = root.right ? getHeight(root.right) + 1 : 0
        res = Math.max(left + right, res)
        return Math.max(left, right)
    }
    getHeight(root)
    return res
};

leetcode 559. N叉树的最大深度

题目地址:N叉树的最大深度

解法一: 迭代,层序遍历

/**
 * // Definition for a Node.
 * function Node(val,children) {
 *    this.val = val;
 *    this.children = children;
 * };
 */
/**
 * @param {Node} root
 * @return {number}
 */
var maxDepth = function(root) {
    if (!root) {
        return 0
    }
    let stack = [{ node: root, level: 1 }]
    let max = 1
    while (stack.length) {
        const temp = stack.shift()
        const node = temp.node
        const level = temp.level
        max = Math.max(level, max)
        if (node.children && node.children.length) {
            for (let i = 0; i < node.children.length; i++) {
                stack.push({node: node.children[i], level: level + 1})
            }
        }
    }
    return max
};

解法二: 递归

var maxDepth = function(root) {
  if(!root) { 
    return 0
  }
  let depth = 0                      
  if(root.children){
    root.children.forEach(item=>{   
      let max = maxDepth(item)      
      depth = Math.max(max, depth)      
    })
  }
  return depth + 1                    
};

leetcode 563. 二叉树的坡度

题目地址:二叉树的坡度

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var findTilt = function(root) {
    let sum = 0
    function getSum (root) {
        if (!root) {
            return 0
        }
        const leftSum = getSum(root.left)
        const rightSum = getSum(root.right)
        sum += Math.abs(leftSum - rightSum)
        return leftSum + rightSum + root.val
    }
    getSum(root)
    return sum
};

leetcode 572. 另一个树的子树

题目地址:另一个树的子树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} s
 * @param {TreeNode} t
 * @return {boolean}
 */
// 遍历树s,判断s是否包含t
var isSubtree = function(s, t) {
    if (!s) return false;
    
    if (_isSubtree(s, t)) return true;
    return isSubtree(s.left, t) || isSubtree(s.right, t);
};

// s是否和t是相同的树
function _isSubtree(s, t) {
    if (!s && !t) return true;
    if (!s || !t) return false;
    if (s.val != t.val) return false;
    return _isSubtree(s.left, t.left) && _isSubtree(s.right, t.right);
}

leetcode 589. N叉树的前序遍历

题目地址:N叉树的前序遍历

递归很简单,只提供迭代算法

/**
 * // Definition for a Node.
 * function Node(val, children) {
 *    this.val = val;
 *    this.children = children;
 * };
 */
/**
 * @param {Node} root
 * @return {number[]}
 */
var preorder = function(root) {
    const res = []
    if (root) {
        const temp = [root]
        while (temp.length) {
            const node = temp.pop()
            res.push(node.val)
            for (let i = node.children.length - 1; i >= 0 ; i--) {
                temp.push(node.children[i])
            }
        }
    }
    return res
};

leetcode 590. N叉树的后序遍历

题目地址:N叉树的后序遍历

解法一:递归

/**
* // Definition for a Node.
* function Node(val,children) {
*    this.val = val;
*    this.children = children;
* };
*/
/**
* @param {Node} root
* @return {number[]}
*/
// 递归
var postorder = function(root) {
    function _postorder (root) {
        if (!root) {
            return
        }
        const children = root.children
        const len = children.length
        for (let i = 0; i < len; i++) {
            _postorder(children[i])
        }
        res.push(root.val)
    }
    const res = []
    root && _postorder(root)
    return res
};

解法二:迭代

/**
* // Definition for a Node.
* function Node(val,children) {
*    this.val = val;
*    this.children = children;
* };
*/
/**
* @param {Node} root
* @return {number[]}
*/
 // 迭代
var postorder = function(root) {
    const res = []
    if (root) {
        const res = [], temp = [root]
        while (temp.length) {
            const node = temp.pop()
            for (let i = 0; i < node.children.length; i++) {
                temp.push(node.children[i])
            }
            res.unshift(node.val)
        }
    }
    return res
};

leetcode 617. 合并二叉树

题目地址:合并二叉树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} t1
 * @param {TreeNode} t2
 * @return {TreeNode}
 */
var mergeTrees = function(t1, t2) {
    if(!t1){
        return t2
    }else if(!t2){
        return t1
    }else{
        t2.val = t1.val + t2.val
        t2.left = mergeTrees(t1.left, t2.left)
        t2.right = mergeTrees(t1.right, t2.right)
        return t2
    }  
};

leetcode 637. 二叉树的层平均值

题目地址:二叉树的层平均值

解法一:广度优先搜索(BFS)

/**
* Definition for a binary tree node.
* function TreeNode(val) {
*     this.val = val;
*     this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var averageOfLevels = function(root) {
    let res = []
    if (root) {
        let queue = [root]
        while (queue.length) {
            const len = queue.length
            let sum = 0
            for (let i = 0; i < len; i++) {
                const node = queue.shift()
                sum += node.val
                node.left && queue.push(node.left)
                node.right && queue.push(node.right)
            }
            res.push(sum / len)
        }
    }
    return res
}; 

解法二:深度优先搜索(DFS)

/**
* Definition for a binary tree node.
* function TreeNode(val) {
*     this.val = val;
*     this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var averageOfLevels = function(root) {
    let temp = []
    let res = []
    let queue = []
    if (root) {
        let level = 0
        queue.push({ node: root, level })
        while (queue.length) {
            const item = queue.shift()
            const node = item.node
            const level = item.level
            if (level === temp.length) {
                temp.push([])
            }
            temp[level].push(node.val)
            node.left && queue.push({ node: node.left, level: level + 1 })
            node.right && queue.push({ node: node.right, level: level + 1 })
        }
    }
    if (temp.length) {
        for (let i = 0; i < temp.length; i++) {
            const arr = temp[i]
            const sum = arr.reduce((a, b) => a + b)
            const average = sum / arr.length
            res.push(average)
        }
    }
    return res
};

leetcode 662. 二叉树最大宽度

题目地址:二叉树最大宽度

 /**
* Definition for a binary tree node.
* function TreeNode(val) {
*     this.val = val;
*     this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var widthOfBinaryTree = function(root) {
    if (!root) {
        return 0
    }
    const queue = [{ node: root, index: 1 }]
    let max = 1
    while (queue.length) {
        const len = queue.length
        // 这一层的长度为1不需要计算宽度
        if (len > 1) {
            const start = queue[0].index
            const end = queue[len - 1].index
            const width = end - start + 1
            max = Math.max(max, width)
        }
        for (let i = 0; i < len; i++) {
            const temp = queue.shift()
            const node = temp.node
            const index = temp.index
            // 层序遍历过程中,用index来维护节点索引,一个节点索引是index,那他的左孩子索引是index * 2,右孩子索引是index * 2 +1
            node.left && queue.push({ node: node.left, index: index * 2 })
            node.right && queue.push({ node: node.right, index: index * 2 + 1 })
        }
    }
    return max
};

leetcode 894. 所有可能的满二叉树

题目地址:所有可能的满二叉树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number} N
 * @return {TreeNode[]}
 */
var allPossibleFBT = function(N) {
    const map = new Map()
    // 数据缓存,map中已有则不再重复计算
    if (!map.has(N)) {
        const ans = []
        if (N === 1) {
            ans.push(new TreeNode(0))
        // 只有N为奇数的时候,才满足构成满二叉树
        } else if (N % 2 === 1) {
            for (let i = 0; i < N; i++) {
                const j = N - i - 1
                // 对于每一个i作为构建一个树的做节点的节点个树
                let leftNodes = allPossibleFBT(i)
                // 构成右节点的节点个树是N - j - 1,减去的1是节点本身
                let rightNodes = allPossibleFBT(j)
                // 循环枚举所有可能
                leftNodes.forEach(left => {
                    rightNodes.forEach(right => {
                        // 根节点
                        const node = new TreeNode(0)
                        node.left = left
                        node.right = right
                        ans.push(node)
                    })
                })
            }
        }
        map.set(N, ans)
    }
    return map.get(N)
};

leetcode 938. 二叉搜索树的范围和

题目地址:二叉搜索树的范围和

对于二叉搜索树,中序遍历就是从小到大的顺序

/**
* Definition for a binary tree node.
* function TreeNode(val) {
*     this.val = val;
*     this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {number} L
* @param {number} R
* @return {number}
*/
var rangeSumBST = function(root, L, R) {
    const stack = []
    let node = root;
    let sum = 0
    while (stack.length > 0 || node !== null) {
        if (node) {
            stack.push(node);
            node = node.left
        } else {
            node = stack.pop();
            if (node.val >= L && node.val <= R) {
                sum += node.val
            }
            node = node.right;
        }
    }
    return sum
};

leetcode 958. 二叉树的完全性检验

题目地址:二叉树的完全性检验

/**
* Definition for a binary tree node.
* function TreeNode(val) {
*     this.val = val;
*     this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isCompleteTree = function(root) {
    if (!root) {
        return true
    }
    const queue = [{ node: root, index: 1 }]
    let count = 0
    while (queue.length) {
        const temp = queue.shift()
        const node = temp.node
        const index = temp.index
        // 用来判断索引位置节点是否存在,如果index !== ++count代表左右子树层级相差超过1层,或者最后一层没有左节点却有右节点
        if (index !== ++count) {
            return false
        }
        // 层序遍历过程中,用index来维护节点索引,如果根节点index为1,那么一个节点索引是index,那他的左孩子索引是index * 2,右孩子索引是index * 2 +1
        node.left && queue.push({ node: node.left, index: index * 2 })
        node.right && queue.push({ node: node.right, index: index * 2 + 1 })
    }
    return true
};

leetcode 965. 单值二叉树

题目地址:单值二叉树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isUnivalTree = function(root) {
    if (!root) {
        return true 
    }
    const val = root.val
    function _isUnivalTree (root) {
        if (root) {
            if (root.val != val) {
                return false
            } else {
                return _isUnivalTree(root.left) && _isUnivalTree(root.right)
            }
        } else {
            return true
        }
    } 
    return _isUnivalTree(root)
};

leetcode 1008. 先序遍历构造二叉树

题目地址:先序遍历构造二叉树

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number[]} preorder
 * @return {TreeNode}
 */
var bstFromPreorder = function(preorder) {
    const len = preorder.length
    if (!len) {
        return null
    }
    const left = []
    const right = []
    const rootVal = preorder[0]
    const root = new TreeNode(rootVal)
    for (let i = 1; i < len; i++) {
        const nodeVal = preorder[i]
        nodeVal > rootVal ? right.push(nodeVal) : left.push(nodeVal)
    }
    root.left = bstFromPreorder(left)
    root.right = bstFromPreorder(right)
    return root
};