- 96. 不同的二叉搜索树">96. 不同的二叉搜索树
 - 108. 将有序数组转换为二叉搜索树">108. 将有序数组转换为二叉搜索树
 - 109. 有序链表转换二叉搜索树">109. 有序链表转换二叉搜索树
 - 95. 不同的二叉搜索树 II">95. 不同的二叉搜索树 II
 - 剑指 Offer 36. 二叉搜索树与双向链表">剑指 Offer 36. 二叉搜索树与双向链表
 - 98. 验证二叉搜索树(判断一棵树是否为二叉搜索树)">98. 验证二叉搜索树(判断一棵树是否为二叉搜索树)
 - 173. 二叉搜索树迭代器">173. 二叉搜索树迭代器
 - 剑指 Offer II 053. 二叉搜索树中的中序后继">剑指 Offer II 053. 二叉搜索树中的中序后继
 - 普通二叉树的中序后继
 
96. 不同的二叉搜索树
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
 
示例 1:
输入:n = 3
输出:5
示例 2:
输入:n = 1
输出:1
 
提示:
1 <= n <= 19
思路:
线性DP
class Solution {public int numTrees(int n) {int[] f = new int[n + 1];f[0] = f[1] = 1;for (int i = 2; i <= n; i++) {for (int j = 1; j <= i; j++) {f[i] += f[j - 1] * f[i - j];}}return f[n];}}
108. 将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
 
示例 1:
输入:nums = [-10,-3,0,5,9]输出:[0,-3,9,-10,null,5]解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:
示例 2:
输入:nums = [1,3]
输出:[3,1]
解释:[1,3] 和 [3,1] 都是高度平衡二叉搜索树。
 
提示:
1 <= nums.length <= 104-104 <= nums[i] <= 104nums按 严格递增 顺序排列
思路:递归自上而下建立整棵树即可!
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/class Solution {public TreeNode sortedArrayToBST(int[] nums) {int n = nums.length;if (n == 0)return null;TreeNode root = new TreeNode(nums[n / 2]);root.left = dfs(nums, 0, n / 2 - 1);root.right = dfs(nums, n / 2 + 1, n - 1);return root;}TreeNode dfs(int[] nums, int l, int r) {if (l > r)return null;int mid = l + r >> 1;TreeNode cur = new TreeNode(nums[mid]);cur.left = dfs(nums, l, mid - 1);cur.right = dfs(nums, mid + 1, r);return cur;}}
109. 有序链表转换二叉搜索树
给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定的有序链表: [-10, -3, 0, 5, 9],
一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:
      0
     / \
   -3   9
   /   /
 -10  5
思路:
- 遍历一遍链表得到长度
 - 用108的方法建一棵空树
 - 中序遍历填充每个节点
 
巧妙选择遍历方案避免链表不能随机访问的缺点!
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*//*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/class Solution {ListNode gg;public TreeNode sortedListToBST(ListNode head) {ListNode cur = head;gg = head;int len = 0;while (cur != null) {cur = cur.next;len++;}// System.out.println(len);TreeNode root = dfs1(0, len - 1);dfs2(root);return root;}TreeNode dfs1(int l, int r) {if (l > r)return null;int mid = l + r >> 1;TreeNode cur = new TreeNode();cur.left = dfs1(l, mid - 1);cur.right = dfs1(mid + 1, r);return cur;}void dfs2(TreeNode root) {if (root == null)return;dfs2(root.left);root.val = gg.val;gg = gg.next;dfs2(root.right);}}
95. 不同的二叉搜索树 II
难度中等1024收藏分享切换为英文接收动态反馈
给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
 
示例 1:
输入:n = 3
输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]
示例 2:
输入:n = 1
输出:[[1]]
 
提示:
1 <= n <= 8
思路:
在96的基础上,不问个数,而是要求输出每一种情况的根节点构成的链表
也用到了108的类似转换方法
我当时的问题:怎么递归保存所有的结果?
是我太年轻了,还是得再暴力一点才能做出来
对于每个根节点来说,生成它的左右子树的所有情况并做拼接
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/class Solution {public List<TreeNode> generateTrees(int n) {return dfs(1, n);}List<TreeNode> dfs(int l, int r) {if (l > r) {List<TreeNode> res = new ArrayList<>();res.add(null);return res;}List<TreeNode> res = new ArrayList<>();for (int i = l; i <= r; i++) {List<TreeNode> ll = dfs(l, i - 1);List<TreeNode> rr = dfs(i + 1, r);for (TreeNode lo : ll) {for (TreeNode ro : rr) {TreeNode root = new TreeNode(i, lo, ro);res.add(root);}}}return res;}}
剑指 Offer 36. 二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
 
为了让您更好地理解问题,以下面的二叉搜索树为例:
 
 
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
 
 
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
 
思路:
先序遍历,不要被二叉搜索树的中序遍历给干扰!
递归得到当前根节点左右子树的双向链表,再将根节点合并到双向链表中!
/*// Definition for a Node.class Node {public int val;public Node left;public Node right;public Node() {}public Node(int _val) {val = _val;}public Node(int _val,Node _left,Node _right) {val = _val;left = _left;right = _right;}};*/class Solution {public Node treeToDoublyList(Node root) {if (root == null)return null;Pair p = dfs(root);p.left.left = p.right;p.right.right = p.left;return p.left;}Pair dfs(Node root) {if (root.left == null && root.right == null)return new Pair(root, root);else if (root.left != null && root.right != null) {Pair p = dfs(root.left);Pair q = dfs(root.right);p.right.right = root;root.left = p.right;q.left.left = root;root.right = q.left;return new Pair(p.left, q.right);} else if (root.left != null) {Pair p = dfs(root.left);p.right.right = root;root.left = p.right;return new Pair(p.left, root);} else {Pair q = dfs(root.right);q.left.left = root;root.right = q.left;return new Pair(root, q.right);}}}class Pair {Node left, right;Pair(Node left, Node right) {this.left = left;this.right = right;}}
98. 验证二叉搜索树(判断一棵树是否为二叉搜索树)
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
 - 节点的右子树只包含 大于 当前节点的数。
 所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:root = [2,1,3]
输出:true
示例 2:
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。
 
提示:
- 树中节点数目范围在
[1, 104]内 -231 <= Node.val <= 231 - 1
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/class Solution {long min = Long.MIN_VALUE;public boolean isValidBST(TreeNode root) {return dfs(root);}boolean dfs(TreeNode root) {if (root == null)return true;if (!dfs(root.left))return false;if (root.val <= min)return false;min = root.val;return dfs(root.right);}}
173. 二叉搜索树迭代器
实现一个二叉搜索树迭代器类BSTIterator ,表示一个按中序遍历二叉搜索树(BST)的迭代器:
BSTIterator(TreeNode root)初始化BSTIterator类的一个对象。BST 的根节点root会作为构造函数的一部分给出。指针应初始化为一个不存在于 BST 中的数字,且该数字小于 BST 中的任何元素。boolean hasNext()如果向指针右侧遍历存在数字,则返回true;否则返回false。int next()将指针向右移动,然后返回指针处的数字。
注意,指针初始化为一个不存在于 BST 中的数字,所以对 next() 的首次调用将返回 BST 中的最小元素。
你可以假设 next() 调用总是有效的,也就是说,当调用 next() 时,BST 的中序遍历中至少存在一个下一个数字。
 
示例:
输入
[“BSTIterator”, “next”, “next”, “hasNext”, “next”, “hasNext”, “next”, “hasNext”, “next”, “hasNext”]
[[[7, 3, 15, null, null, 9, 20]], [], [], [], [], [], [], [], [], []]
输出
[null, 3, 7, true, 9, true, 15, true, 20, false]
解释
BSTIterator bSTIterator = new BSTIterator([7, 3, 15, null, null, 9, 20]);
bSTIterator.next();    // 返回 3
bSTIterator.next();    // 返回 7
bSTIterator.hasNext(); // 返回 True
bSTIterator.next();    // 返回 9
bSTIterator.hasNext(); // 返回 True
bSTIterator.next();    // 返回 15
bSTIterator.hasNext(); // 返回 True
bSTIterator.next();    // 返回 20
bSTIterator.hasNext(); // 返回 False
 
提示:
- 树中节点的数目在范围 
[1, 105]内 0 <= Node.val <= 106最多调用
105次hasNext和next操作
进阶:你可以设计一个满足下述条件的解决方案吗?
next()和hasNext()操作均摊时间复杂度为O(1),并使用O(h)内存。其中h是树的高度。
思路:
使用自定义栈进行中序遍历
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/class BSTIterator {Deque<TreeNode> stack = new LinkedList<>();public BSTIterator(TreeNode root) {while (root != null) {stack.push(root);root = root.left;}}public int next() {TreeNode cur = stack.pop();int x = cur.val;if (cur.right != null) {cur = cur.right;while (cur != null) {stack.push(cur);cur = cur.left;}}return x;}public boolean hasNext() {return !stack.isEmpty();}}/*** Your BSTIterator object will be instantiated and called as such:* BSTIterator obj = new BSTIterator(root);* int param_1 = obj.next();* boolean param_2 = obj.hasNext();*/
剑指 Offer II 053. 二叉搜索树中的中序后继
给定一棵二叉搜索树和其中的一个节点 p ,找到该节点在树中的中序后继。如果节点没有中序后继,请返回 null 。
节点 p 的后继是值比 p.val 大的节点中键值最小的节点,即按中序遍历的顺序节点 p 的下一个节点。
示例 1:
输入:root = [2,1,3], p = 1 输出:2 解释:这里 1 的中序后继是 2。请注意 p 和返回值都应是 TreeNode 类型。 
示例 2:
输入:root = [5,3,6,2,4,null,null,1], p = 6 输出:null 解释:因为给出的节点没有中序后继,所以答案就返回 null 了。 
提示:
- 树中节点的数目在范围 [1, 104] 内。
 - -105 <= Node.val <= 105
 - 树中各节点的值均保证唯一。
 
思路:
因为是二叉搜索树,所以给定节点的中序后继就是第一个比它节点存的值大的节点。
只需扫描目标节点所在的分支(指一条完整的从根节点到叶节点的路径,其中包括目标节点,如果存在的话)即可找到第一个比他大的节点。
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/class Solution {public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {TreeNode ans = null, cur = root;while (cur != null) {if (cur.val > p.val) {ans = cur;cur = cur.left;} else {cur = cur.right;}}return ans;}}
普通二叉树的中序后继
思路:
利用中序遍历,记录目标节点是否已经被访问到,若目标节点已经被访问到,则接下来遍历的第一个节点就是其后继
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/class Solution {TreeNode ans;boolean flag;public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {dfs(root, p);return ans;}void dfs(TreeNode root, TreeNode p) {if (root == null) return;dfs(root.left, p);if (flag && ans == null)ans = root;if (root == p)flag = true;dfs(root.right, p);}}
