验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
输出: true
示例 2:
输入:
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4
中序遍历
class Solution {
private long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if (root == null)
return true;
if (!isValidBST(root.left))
return false;
if (root.val <= pre)
return false;
pre = root.val;
return isValidBST(root.right);
}
}
递归
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean isValidBST(TreeNode root, long min, long max) {
if (root == null)
return true;
if (root.val <= min || root.val >= max)
return false;
return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max);
}
}
恢复二叉搜索树
给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?
示例 1:
输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。
示例 2:
输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。
中序遍历,数组存储
class Solution {
public void recoverTree(TreeNode root) {
List<TreeNode> list = new ArrayList<TreeNode>();
inorder(root, list);
TreeNode wrong1 = null, wrong2 = null;
for (int i = 0; i < list.size() - 1; i++) {
if (list.get(i).val > list.get(i + 1).val) {
wrong1 = list.get(i + 1);
if (wrong2 == null)
wrong2 = list.get(i);
}
}
int tmp = wrong1.val;
wrong1.val = wrong2.val;
wrong2.val = tmp;
}
public void inorder(TreeNode root, List<TreeNode> list) {
if (root == null)
return;
inorder(root.left, list);
list.add(root);
inorder(root.right, list);
}
}
中序遍历,存储节点
class Solution {
private TreeNode wrong1 = null;
private TreeNode wrong2 = null;
private TreeNode pre = null;
private int count = 0;
public void recoverTree(TreeNode root) {
inorder(root);
int tmp = wrong1.val;
wrong1.val = wrong2.val;
wrong2.val = tmp;
}
public void inorder(TreeNode root) {
if (count >= 2 || root == null)
return;
inorder(root.left);
if (pre == null) {
pre = root;
} else {
if (pre.val > root.val) {
count++;
wrong1 = root;
if (wrong2 == null)
wrong2 = pre;
}
pre = root;
}
inorder(root.right);
}
}
莫里斯遍历
可以做到 O(1) 的空间复杂度去遍历一棵树。
class Solution {
public void recoverTree(TreeNode root) {
if(root==null)
return;
TreeNode wrong1 = null, wrong2 = null;
TreeNode pre = null, node = null;
while(root!=null) {
if(root.left != null) {
node = root.left;
while(node.right != null && node.right != root)
node = node.right;
if(node.right == null) {
node.right = root;
root = root.left;
} else {
if(pre != null && pre.val > root.val) {
wrong1 = root;
if(wrong2 == null)
wrong2 = pre;
}
pre = root;
node.right = null;
root = root.right;
}
} else {
if(pre != null && pre.val > root.val) {
wrong1 = root;
if(wrong2 == null)
wrong2 = pre;
}
pre = root;
root = root.right;
}
}
int tmp = wrong1.val;
wrong1.val = wrong2.val;
wrong2.val = tmp;
}
}
二叉搜索树中第K小的元素
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。
示例 1:
输入:root = [3,1,4,null,2], k = 1
输出:1
示例 2:
输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3
迭代
class Solution {
public int kthSmallest(TreeNode root, int k) {
Deque<TreeNode> stack = new LinkedList<>();
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (0 == --k)
return root.val;
root = root.right;
}
return 0;
}
}
递归
class Solution {
public int kthSmallest(TreeNode root, int k) {
return inorder(root, k, new ArrayList<Integer>()).get(k - 1);
}
private List<Integer> inorder(TreeNode root, int k, List<Integer> list) {
if (root == null || list.size() == k)
return list;
inorder(root.left, k, list);
list.add(root.val);
inorder(root.right, k, list);
return list;
}
}
二叉搜索树中的众数
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
- 结点左子树中所含结点的值小于等于当前结点的值
- 结点右子树中所含结点的值大于等于当前结点的值
- 左子树和右子树都是二叉搜索树
例如:
给定 BST [1,null,2,2],
返回[2].
提示:如果众数超过1个,不需考虑输出顺序
中序遍历
class Solution {
private List<Integer> result = new ArrayList<>();
private int count = 0, cur_val = 0, max_count = 0;
public int[] findMode(TreeNode root) {
inorder(root);
int[] ans = new int[result.size()];
for (int i = 0; i < result.size(); i++)
ans[i] = result.get(i);
return ans;
}
private void inorder(TreeNode node) {
if (node == null)
return;
inorder(node.left);
int val = node.val;
if (val == cur_val) {
count++;
} else {
cur_val = val;
count = 1;
}
if (count == max_count)
result.add(val);
else if (count > max_count) {
result.clear();
result.add(val);
max_count = count;
}
inorder(node.right);
}
}
Morris遍历
class Solution {
private int cur_val = 0, count = 0, maxCount = 0;
private List<Integer> answer = new ArrayList<Integer>();
public int[] findMode(TreeNode root) {
TreeNode cur = root, pre = null;
while (cur != null) {
if (cur.left == null) {
update(cur.val);
cur = cur.right;
continue;
}
for (pre = cur.left; pre.right != null && pre.right != cur; pre = pre.right);
if (pre.right == null) {
pre.right = cur;
cur = cur.left;
} else {
pre.right = null;
update(cur.val);
cur = cur.right;
}
}
int[] result = new int[answer.size()];
for (int i = 0; i < answer.size(); ++i)
result[i] = answer.get(i);
return result;
}
private void update(int x) {
if (x == cur_val) {
++count;
} else {
count = 1;
cur_val = x;
}
if (count == maxCount) {
answer.add(x);
} else if (count > maxCount) {
maxCount = count;
answer.clear();
answer.add(x);
}
}
}
二叉树中第二小的节点
给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。
更正式地说,root.val = min(root.left.val, root.right.val) 总成立。
给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。
示例 1:
输入:root = [2,2,5,null,null,5,7]
输出:5
解释:最小的值是 2 ,第二小的值是 5 。
示例 2:
输入:root = [2,2,2]
输出:-1
解释:最小的值是 2, 但是不存在第二小的值。
递归
class Solution {
private int result = -1;
public int findSecondMinimumValue(TreeNode root) {
if (root == null)
return result;
if (root.left != null && root.left.val != root.right.val) {
int larger = Math.max(root.left.val, root.right.val);
result = result == -1 ? larger : Math.min(result, larger);
findSecondMinimumValue(root.left.val > root.right.val ? root.right : root.left);
} else {
findSecondMinimumValue(root.left);
findSecondMinimumValue(root.right);
}
return result;
}
}