数据结构-二叉树二

333 阅读12分钟

构造二叉树

根据前序和后序遍历构造二叉树

返回与给定的前序和后序遍历匹配的任何二叉树。

输入:pre = [1,2,4,5,3,6,7], post = [4,5,2,6,7,3,1]
输出:[1,2,3,4,5,6,7]

来源: leetcode-cn.com/problems/co…

var constructFromPrePost = function(pre, post) {
    if(!pre.length || !post.length) return null;
    const node = new TreeNode(pre.shift());
    post.pop();
    let idx = pre.indexOf(post[post.length - 1]);
    node.left = constructFromPrePost(pre.slice(0, idx), post.slice(0, idx));
    node.right = constructFromPrePost(pre.slice(idx), post.slice(idx));
    return node;
};

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

根据一棵树的前序遍历与中序遍历构造二叉树。

输入:前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7]

    3
   / \
  9  20
    /  \
   15   7

来源: leetcode-cn.com/problems/co…

var buildTree = function(preorder, inorder) {
    if(!preorder.length || !inorder.length) return null;
    const rootVal = preorder[0];
    const node = new TreeNode(rootVal);
    let i = 0;
    for (; i < inorder.length; i++) {
        if(inorder[i] === rootVal) {
            break;
        }
    }
    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;
};

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

根据一棵树的中序遍历与后序遍历构造二叉树。

输入:中序遍历 inorder = [9,3,15,20,7] 后序遍历 postorder = [9,15,7,20,3]

    3
   / \
  9  20
    /  \
   15   7

来源: leetcode-cn.com/problems/co…

var buildTree = function(inorder, postorder) {
    if(!inorder.length || !postorder.length) return null;
    const rootVal = postorder[postorder.length - 1];
    let i = 0;
    for (; i < inorder.length; i++) {
        if(inorder[i] === rootVal) {
            break;
        }
    }
    postorder.pop();
    const node = new TreeNode(rootVal);
    node.left = buildTree(inorder.slice(0, i), postorder.slice(0, i));
    node.right = buildTree(inorder.slice(i + 1), postorder.slice(i));
    return node;
};

前序遍历构造二叉搜索树

返回与给定前序遍历 preorder 相匹配的二叉搜索树(binary search tree)的根结点

输入:[8,5,1,7,10,12]
输出:[8,5,10,1,7,null,12]

来源: leetcode-cn.com/problems/co…

var bstFromPreorder = function(preorder) {
    if(!preorder.length) return null;
    let root = new TreeNode(preorder.shift());
    let idx = preorder.findIndex(item => item > root.val);
    idx = idx === -1 ? preorder.length : idx;
    root.left = bstFromPreorder(preorder.slice(0, idx));
    root.right = bstFromPreorder(preorder.slice(idx));
    return root;   
};

从先序遍历还原二叉树

我们从二叉树的根节点 root 开始进行深度优先搜索。 在遍历中的每个节点处,我们输出 D 条短划线(其中 D 是该节点的深度),然后输出该节点的值。(如果节点的深度为 D,则其直接子节点的深度为 D + 1。根节点的深度为 0)。 如果节点只有一个子节点,那么保证该子节点为左子节点。 给出遍历输出 S,还原树并返回其根节点 root

输入:"1-2--3--4-5--6--7"
输出:[1,2,5,3,4,6,7]

来源: leetcode-cn.com/problems/re…

var recoverFromPreorder = function(S) {
    let stack = [];
    let i = findNum(S, 0);
    let root = new TreeNode(Number(S.substr(0, i)));
    stack.push(root);
    for(; i < S.length;) {
        let r = findDepth(S, i);
        while(stack.length > r - i) {
            stack.pop();
        }
        let node = stack[stack.length - 1];
        let e = findNum(S, r);
        let num = Number(S.substr(r, e - r));
        let tmp = new TreeNode(num);
        if(node.left) {
            node.right = tmp;
        } else {
            node.left = tmp;
        }
        stack.push(tmp);
        i = e;
    }
    return root;
};

function findNum(S, i) {
    while(i < S.length && S[i] >= '0' && S[i] <= '9') {
        i++;
    }
    return i;
}
function findDepth(S, i) {
    while(i < S.length && S[i] == '-') {
        i++;
    }
    return i;
}

恢复二叉搜索树

二叉搜索树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。

输入: [1,3,null,null,2]
输出: [3,1,null,null,2]
   1
  /
 3
  \
   2  3
  /
 1
  \
   2

来源: leetcode-cn.com/problems/re…

var recoverTree = function(root) {
    let arr = [];
    function inorder(root) {
        if(!root) return;
        inorder(root.left);
        arr.push(root.val);
        inorder(root.right);
    }
    function fill(root) {
        if(!root) return;
        fill(root.left);
        root.val = arr.shift();
        fill(root.right);
    }
    if(!root) return;
    inorder(root);
    arr.sort((a, b) => a - b);
    fill(root); 
};

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

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点的左右两个子树的高度差的绝对值不超过 1。

输入:[-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:      
      0
     / \
   -3   9
   /   /
 -10  5

来源: leetcode-cn.com/problems/co…

var sortedArrayToBST = function(nums) {
    let help = (start, end) => {
        if(start > end) return null;
        if(start === end) return new TreeNode(nums[start]);
        let mid = (start + end) >> 1;
        let node = new TreeNode(nums[mid]);
        node.left = help(start, mid - 1);
        node.right = help(mid + 1, end);
        return node;
    }
    return help(0, nums.length - 1);
};

所有可能的满二叉树

满二叉树是一类二叉树,其中每个结点恰好有 0 或 2 个子结点。 返回包含 N 个结点的所有可能满二叉树的列表。 答案的每个元素都是一个可能树的根结点。 答案中每个树的每个结点都必须有 node.val=0。 你可以按任何顺序返回树的最终列表。  

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

来源: leetcode-cn.com/problems/al…

var allPossibleFBT = function(N) {
    let memo = new Map();
    let res = [];
    if(N === 1) {
        res.push(new TreeNode(0));
        return res;
    } else if(memo.has(N)) {
        return memo(N)
    } else {
        for (let i = 1; i < N; i += 2) {
            let leftAll = allPossibleFBT(i);
            let rightAll = allPossibleFBT(N - i - 1);
            for (let left of leftAll) {
                for (let right of rightAll) {
                    let root = new TreeNode(0);
                    root.left = left;
                    root.right = right;
                    res.push(root)
                }
            }
        }
    }
    memo.set(N, res);
    return res;
};

路径/和问题

路径总和

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

输入: 
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1
sum: 22

输出: true
解释: 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2

来源: leetcode-cn.com/problems/pa…

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))
};

路径总和 II

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

输入: 
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1
sum: 22

输出: [   [5,4,11,2],
   [5,8,4,5]
]

来源: leetcode-cn.com/problems/pa…

DFS+回溯方法实现:

var pathSum = function(root, sum) {
    let res = [], path = [];
    help(root, sum, res, path);
    function help(node, sum, res, path) {
        if(!node) return;
        path.push(node.val);
        if(sum === node.val && !node.left && !node.right) {
            res.push(path.slice())
        }
        help(node.left, sum - node.val, res, path);
        help(node.right, sum - node.val, res, path);
        path.pop();
    }
    return res;
};

路径总和 III

给定一个二叉树,它的每个结点都存放着一个整数值。 找出路径和等于给定数值的路径总数。 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

输入: 
       10    
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1
sum: 8
返回 3。和等于 8 的路径有:
1\.  5 -> 3
2\.  5 -> 2 -> 1
3\.  -3 -> 11

来源: leetcode-cn.com/problems/pa…

DFS实现:

function dfs(cur,sum,root,path,res){
    cur += root.val;
    path.push(root.val);
    if(cur === sum && !root.left && !root.right){
        res.push(path.slice(0));
    }
    root.left && dfs(cur,sum,root.left,path,res);
    root.right && dfs(cur,sum,root.right,path,res);
    path.pop();
}
var pathSum = function(root, sum) {
    if(!root) return [];
    let res = [],path = [],cur = 0;
    dfs(cur,sum,root,path,res);
    return res;
}; 

二叉树中的最大路径和

给定一个非空二叉树,返回其最大路径和。 本题中,路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。

输入: [-10,9,20,null,null,15,7]
    -10   
   / \
  9  20
    /  \
   15   7 

输出: 42

来源: leetcode-cn.com/problems/bi…

var maxPathSum = function(root) {
    let ans = -Infinity;
    function dfs (node) {
        if(!node) return 0;
        let left = Math.max(0, dfs(node.left));
        let right = Math.max(0, dfs(node.right));
        ans = Math.max(ans, left + right + node.val);
        return Math.max(left, right) + node.val;
    }
    dfs(root);
    return ans;
};

二叉树的直径

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

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

来源: leetcode-cn.com/problems/di…

var diameterOfBinaryTree = function(root) {
    let max = 0;
    if(root === 0) return 0;
    const help = (node) => {
        if(node === null) return 0;
        let left = node.left ? help(node.left) + 1 : 0;
        let right = node.right ? help(node.right) + 1 : 0;
        let cur = left + right;
        if(cur > max) max = cur;
        return Math.max(left, right);
    }
    help(root);
    return max;
};

二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

输入: 
         1      
       /   \
      2     3
       \
        5
输出: ["1->2->5", "1->3"]

解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3

来源: leetcode-cn.com/problems/bi…

var binaryTreePaths = function(root) {
    let path = [], res = [];
    let dfs = (node) => {
        if(!node) return;
        path.push(node);
        dfs(node.left);
        dfs(node.right);
        if(!node.left && !node.right) {
            res.push(path.map(item => item.val).join('->'))
        }
        path.pop()
    }
    dfs(root);
    return res;
};

层数最深叶子节点的和

给你一棵二叉树,请你返回层数最深的叶子节点的和。

输入:root = [1,2,3,4,5,null,6,7,null,null,null,null,8]
输出:15

来源: leetcode-cn.com/problems/de…

BFS实现:

var deepestLeavesSum = function(root) {
    let queue = [root];
    let ans = 0;
    while(queue.length) {
        let len = queue.length;
        ans = 0;
        while(len--) {
            let node = queue.shift();
            ans += node.val;
            if(node.left) {
                queue.push(node.left)
            }
            if(node.right) {
                queue.push(node.right)
            }
        }
    }
    return ans;
};

DFS实现:

var deepestLeavesSum = function(root) {
    let stack = [root], sum = 0, levle = 0, maxLevel = 0;
    let fn = (root, levle) => {
        if(!root) return
        if(levle > maxLevel) {
            maxLevel = levle;
            sum = 0
        }
        if(root.left === null && root.right === null && levle === maxLevel) sum += root.val;
        if(root.left) {
            fn(root.left, levle + 1);
        }
        if(root.right) {
            fn(root.right, levle + 1)
        }
    }
    fn(root, 0);
    return sum;
}

出现次数最多的子树元素和

给你一个二叉树的根结点,请你找出出现次数最多的子树元素和。一个结点的「子树元素和」定义为以该结点为根的二叉树上所有结点的元素之和(包括结点本身)。 你需要返回出现次数最多的子树元素和。如果有多个元素出现的次数相同,返回所有出现次数最多的子树元素和(不限顺序)。

   5
 /  \
2   -3
返回 [2, -3, 4],所有的值均只出现一次,以任意顺序返回所有值。
  5
 /  \
2   -5返回 [2],只有 2 出现两次,-5 只出现 1 次。

来源: leetcode-cn.com/problems/mo…

var findFrequentTreeSum = function(root) {
    function getSum(node, map, res, max) {
        if(!node) return 0;
        let left = getSum(node.left, map, res, max);
        let right = getSum(node.right, map, res, max);
        let cur = left + right + node.val;
        if(map[cur]) map[cur]++;
        else map[cur] = 1;
        if(max[0] < map[cur]) {
            res.length = 0;
            res.push(cur)
            max[0] = map[cur]
        } else if(max[0] === map[cur]) {
            res.push(cur)
        }
        return cur;
    }
    let res = [];
    let map = {};
    let max = [0];
    getSum(root, map, res, max);
    return res;
};

左叶子之和

计算给定二叉树的所有左叶子之和。

    3
   / \
  9  20
    /  \
   15   7
在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

来源: leetcode-cn.com/problems/su…

var sumOfLeftLeaves = function(root) {
    if(!root) return 0;
    let { left, right } = root;
    if(left && !left.left && !left.right) {
        return root.left.val + sumOfLeftLeaves(right);
    }
    return sumOfLeftLeaves(left) + sumOfLeftLeaves(right);
};

求根到叶子节点数字之和

给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。 例如,从根到叶子节点路径 1->2->3 代表数字 123。 计算从根到叶子节点生成的所有数字之和。 说明: 叶子节点是指没有子节点的节点。

输入: [1,2,3]
    1
   / \
  2   3
输出: 25
解释:
从根到叶子节点路径 1->2 代表数字 12.
从根到叶子节点路径 1->3 代表数字 13.
因此,数字总和 = 12 + 13 = 25.

来源: leetcode-cn.com/problems/su…

var sumNumbers = function(root) {
    if(!root) return 0;
    let help = (root, cur) => {
        if(!root) return;
        cur = cur * 10 + root.val;
        if(!root.left && !root.right) {
            sum += cur;
        }
        return help(root.left, cur) + help(root.right, cur);
    }
    let sum = 0;
    help(root, 0);
    return sum;
};

两数之和 IV - 输入 BST

给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。

输入: 
    5
   / \
  3   6
 / \   \
2   4   7

Target = 9

来源: leetcode-cn.com/problems/tw…

var findTarget = function(root, k) {
    let arr = [], ans = false;
    let help = (node) => {
        if(!node) return;
        help(node.left);
        arr.push(node.val);
        help(node.right);
    }
    help(root);
    let left = 0, right = arr.length - 1;
    while(left < right) {
        let sum = arr[left] + arr[right];
        if(sum === k) {
            ans = true;
            break;
        } else if(sum > k) {
            right--
        } else {
            left++;
        }
    }
    return ans;
};

二叉搜索树

验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树

输入:
    2
   / \
  1   3
输出: true

来源: leetcode-cn.com/problems/va…

//定义法
//根据定义,一个结点若是在根的左子树上,那它应该小于根结点的值而大于左子树最小值;若是在根的右子树上,//那它应该大于根结点的值而小于右子树最大值。也就是说,每一个结点必须落在某个取值范围:

//根结点的取值范围为(考虑某个结点为最大或最小整数的情况):(long_min, long_max)
//左子树的取值范围为:(current_min, root.value)
//右子树的取值范围为:(root.value, current_max)
var isValidBST = function(root) {
    if(!root) return true;
    return valid(root);
};

function valid(root, min = -Infinity, max = Infinity) {
    if(!root) return true;
    const val = root.val;
    if(val <= min) return false;
    if(val >= max) return false;
    return valid(root.left, min, val) && valid(root.right, val, max);
}

有序链表转换二叉搜索树

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

给定的有序链表: [-10, -3, 0, 5, 9],

一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

来源: leetcode-cn.com/problems/co…

var sortedListToBST = function(head) {
    let makeTree = (head, tail) => {
        if(head === tail) return null;
        let p1 = head, p2 = head;
        while(p2 !== tail) {
            p2 = p2.next;
            if(p2 !== tail){
                p1 = p1.next;
                p2 = p2.next;
            }
        }
        var treeNode = new TreeNode(p1.val);
        treeNode.left = makeTree(head, p1);
        treeNode.right = makeTree(p1.next, tail);
        return treeNode;
    }
    return makeTree(head, null);
};

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

给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

输入: root = [5,3,6,2,4,null,null,1], k = 3
       5
      / \
     3   6
    / \
   2   4
  /
 1
输出: 3

来源: leetcode-cn.com/problems/kt…
相似题目: 二叉搜索树的第k大节点: leetcode-cn.com/problems/er…

var kthSmallest = function(root, k) {
    let dfs = (node) => {
        if(!node) return;
        dfs(node.left);
        res.push(node.val);
        dfs(node.right);
    }
    let res = [];
    dfs(root);
    return res[k-1]
};

不同的二叉搜索树

给定一个整数n,求以 1 ...n为节点组成的二叉搜索树有多少种?

输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

来源: leetcode-cn.com/problems/un…

var numTrees = function(n) {
    let res = new Array(n + 1).fill(0);
    res[0] = 1, res[1] = 1;
    for (let i = 2; i <= n; i++) {
        for (let j = 1; j <= i; j++) {
            res[i] += res[j - 1] * res[i - j];
        }
    }
    return res[n];
};

不同的二叉搜索树 II

给定一个整数n,生成所有由 1 ...n为节点所组成的 二叉搜索树

输入:3
输出:
[
  [1,null,3,2],
  [3,2,null,1],
  [3,1,null,null,2],
  [2,1,3],
  [1,null,2,null,3]
]
解释:
以上的输出对应以下 5 种不同结构的二叉搜索树:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

来源: leetcode-cn.com/problems/un…

var generateTrees = function(n) {
    if(n === 0) return [];
    return generate_tree(1, n);    
};

function generate_tree(start, end) {
    const res = [];
    if(start > end) return [null];
    for (let i = start; i <= end; i++) {
        let left_tree = generate_tree(start, i - 1);
        let right_tree = generate_tree(i + 1, end);
        for (const ln of left_tree) {
            for (const rn of right_tree) {
                const cur = new TreeNode(i);
                cur.left = ln;
                cur.right = rn;
                res.push(cur);
            }
        }
    }
    return res;
}

删除二叉搜索树中的节点

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。 一般来说,删除节点可分为两个步骤: 首先找到需要删除的节点; 如果找到了,删除它。 说明: 要求算法时间复杂度为 O(h),h 为树的高度。

root = [5,3,6,2,4,null,7]
key = 3

    5
   / \
  3   6
 / \   \
2   4   7

给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。

一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。

    5
   / \
  4   6
 /     \
2       7

另一个正确答案是 [5,2,6,null,4,null,7]。

    5
   / \
  2   6
   \   \
    4   7

来源: leetcode-cn.com/problems/de…

var deleteNode = function(root, key) {
    if(root === null) return root;
    if(key > root.val) root.right = deleteNode(root.right, ket);
    else if(key  < root.val) root.left = deleteNode(root.left, key);
    else {
        if(root.left === null && root.right === null) root = null;
        else if(root.right !== null) {
            root.val = successor(root);
            root.right = deleteNode(root.right, root.val)
        } else {
            root.val = predecessor(root);
            root.left = deleteNode(root.left, root.val);
        }
    }
    return root;  
};

function successor(root) {
    root = root.right;
    while(root.left !== null) root = root.left;
    return root.val;
}

function predecessor(root) {
    root = root.left;
    while(root.right !== null) root = root.right;
    return root.val;
}

二叉搜索树中的众数

给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。

   1
    \
     2
    /
   2

来源: leetcode-cn.com/problems/fi…

var findMode = function(root) {
    let prenode = null;
    let count = 1;
    let max = 1, res = [];
    let help = (root) => {
        if(!root) return;
        help(root.left);
        if(prenode) {
            if(root.val === prenode.val) count++;
            else count = 1;
        }
        if(count > max) {
            max = count;
            res = [];
            res.push(root.val)
        } else if(count === max) {
            res.push(root.val)
        }
        prenode = root;
        help(root.right);
    }
    help(root);
    return res;
};

二叉搜索树的最小绝对差

给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。

输入:

   1
    \
     3
    /
   2

输出:
1

解释:
最小绝对差为 1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。

来源: leetcode-cn.com/problems/mi…

var getMinimumDifference = function(root) {
    let arr = [];
    let help = (root) => {
        if(!root) return;
        help(root.left);
        arr.push(root.val);
        help(root.right);
    }
    help(root);
    let min = Infinity;
    for (let i = 0; i < arr.length; i++) {
        if(min > arr[i + 1] - arr[i]) {
            min = arr[i + 1] - arr[i]
        }
    }
    return min;
};

修剪二叉搜索树

给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。

输入: 
    3
   / \
  0   4
   \
    2
   /
  1

  L = 1
  R = 3

输出: 
      3
     / 
   2   
  /
 1

来源: leetcode-cn.com/problems/tr…

var trimBST = function(root, low, high) {
    if(!root) return root;
    if(root.val < low) return trimBST(root.right, low, high);
    if(root.val > high) return trimBST(root.left, low, high);
    root.left = trimBST(root.left, low, high);
    root.right = trimBST(root.right, low, high);
    return root;
};

二叉搜索树中的搜索

给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。

给定二叉搜索树:

        4
       / \
      2   7
     / \
    1   3

和值: 2
返回   2     
     / \   
    1   3

来源: leetcode-cn.com/problems/se…

var searchBST = function(root, val) {
    if(!root) return root;
    if(root.val === val) return root;
    return root.val < val ? searchBST(root.right, val) : searchBST(root.left, val);
};

二叉搜索树中的插入操作

给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证,新值和原始二叉搜索树中的任意节点值都不同。

给定二叉搜索树:

        4
       / \
      2   7
     / \
    1   3

和 插入的值: 5
可以返回:
         4
       /   \
      2     7
     / \   /
    1   3 5

来源: leetcode-cn.com/problems/in…

var insertIntoBST = function(root, val) {
    const node = new TreeNode(val);
    if(!root) return root = node;
    if(val < root.val) {
        root.left = insertIntoBST(root.left, val)
    }  else {
        root.right = insertIntoBST(root.right, val);
    }
    return root; 
};

二叉搜索树节点最小距离

给定一个二叉搜索树的根节点 root,返回树中任意两节点的差的最小值。

输入: root = [4,2,6,1,3,null,null]
输出: 1
解释:
注意,root是树节点对象(TreeNode object),而不是数组。

给定的树 [4,2,6,1,3,null,null] 可表示为下图:

          4
        /   \
      2      6
     / \    
    1   3  

最小的差值是 1, 它是节点1和节点2的差值, 也是节点3和节点2的差值。

来源: leetcode-cn.com/problems/mi…

var minDiffInBST = function(root) {
    let arr = [];
    let help = (root) => {
        if(!root) return;
        help(root.left);
        arr.push(root.val);
        help(root.right);
    }
    help(root);
    let min = Infinity;
    for (let i = 0; i < arr.length; i++) {
        if(min > arr[i + 1] - arr[i]) {
            min = arr[i + 1] - arr[i]
        }
    }
    return min;
};

两棵二叉搜索树中的所有元素

给你 root1root2 这两棵二叉搜索树。请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序。

输入:root1 = [2,1,4], root2 = [1,0,3]
输出:[0,1,1,2,3,4]

来源: leetcode-cn.com/problems/al…

var getAllElements = function(root1, root2) {
    let inOrder = (root) => {
        if(!root) return arr;
        inOrder(root.left);
        arr.push(root.val);
        inOrder(root.right);
    }
    let arr = [];
    inOrder(root1);
    inOrder(root2);
    arr.sort((a, b) => a - b);
    return arr;
};

将二叉搜索树变平衡

给你一棵二叉搜索树,请你返回一棵 平衡后 的二叉搜索树,新生成的树应该与原来的树有着相同的节点值。如果一棵二叉搜索树中,每个节点的两棵子树高度差不超过 1 ,我们就称这棵二叉搜索树是 平衡的 。如果有多种构造方法,请你返回任意一种。

输入:root = [1,null,2,null,3,null,4,null,null]
输出:[2,1,3,null,null,null,4]
解释:这不是唯一的正确答案,[3,1,4,null,2,null,null] 也是一个可行的构造方案。

来源: leetcode-cn.com/problems/ba…

var balanceBST = function(root) {
    let valArr = [];
    let help = (root) => {
        if(!root) return;
        help(root.left);
        valArr.push(root.val);
        help(root.right);
    }
    help(root);
    let createTree = (l, r) => {
        if(l > r) return null;
        let mid = (l + r) >> 1;
        let t = new TreeNode(valArr[mid]);
        t.left = createTree(l, mid - 1);
        t.right = createTree(mid + 1, r);
        return t;
    }
    let res = createTree(0, valArr.length - 1);
    return res;
};

二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

输入: [1,6,3,2,5]
输出: false

输入: [1,3,2,6,5]
输出: true

来源: leetcode-cn.com/problems/er…

var verifyPostorder = function(postorder) {
    let stack = [], pre = Number.MAX_VALUE;
    for (let i = postorder.length - 1; i >= 0; i--) {
        if(postorder[i] > pre) {
            return false;
        }
        while(stack.length && postorder[i] < stack[stack.length - 1]) {
            pre = stack.pop()
        }
        stack.push(postorder[i])
    }
    return true;
};

二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

来源: leetcode-cn.com/problems/er…

var treeToDoublyList = function(root) {
    if(!root) return;
    let head = null, pre = head;
    let arr = [];
    let inOrder = (node) => {
        if(!node) return;
        inOrder(node.left);
        arr.push(node);
        inOrder(node.right);
    }
    inOrder(root);
    for (let i = 0; i < arr.length - 1; i++) {
        arr[i].right = arr[i + 1];
        arr[i + 1].left = arr[i]
    }
    arr[arr.length - 1].right = arr[0];
    arr[0].left = arr[arr.length - 1];
    return arr[0]
};

二叉搜索树序列

从左向右遍历一个数组,通过不断将其中的元素插入树中可以逐步地生成一棵二叉搜索树。给定一个由不同节点组成的二叉搜索树,输出所有可能生成此树的数组。

输入
        2
       / \
      1   3
返回
[
   [2,1,3],
   [2,3,1]
]

来源: leetcode-cn.com/problems/bs…

var BSTSequences = function(root) {
    let res = [];
    if(!root) return [[]];
    let queue = [];
    let dfs = (root, res, queue, tmp) => {
        if(!root) return;
        if(root.left) queue.push(root.left);
        if(root.right) queue.push(root.right);
        if(queue.length === 0) {
            res.push([...tmp]);
            return
        }
        let len = queue.length;
        while(len--) {
            let cur = queue.shift();
            dfs(cur, res, queue.slice(), [...tmp, cur.val]);
            queue.push(cur)
        }
    }
    dfs(root, res, queue, [root.val])
    return res;
};