530.二叉搜索树的最小绝对差(BST的中序是有序的)
还是疏忽了……一定要牢记BST的性质。
在BST中,最小绝对差不一定出现在父子节点之间,而是可能出现在相邻的中序遍历节点之间。因此,直接比较当前节点与其左右子节点的值是不够的。
class Solution {
public int getMinimumDifference(TreeNode root) {
min = Integer.MAX_VALUE;
getMin(root);
return min;
}
private int min;
private void getMin(TreeNode node){
if(node==null) return;
if(node.left!=null){
min = min < Math.abs(node.val - node.left.val) ? min : Math.abs(node.val - node.left.val);
getMin(node.left);
}
if(node.right!=null){
min = min < Math.abs(node.val - node.right.val) ? min : Math.abs(node.val - node.right.val);
getMin(node.right);
}
}
}
BST是有序的,可以视为在一个有序数组上求最值,求差值,这样就简单多了。
思路:
- 最直观的想法,就是把二叉搜索树转换成有序数组,然后遍历一遍数组,就统计出来最小差值了(相邻两数的差值)。
- 不需要转换为数组:在BST中序遍历的过程中,我们就可以直接计算了。
需要用一个pre节点记录一下cur节点的前一个节点。
在中序遍历中,由于cur始终比pre快,因此cur.val - pre.val
一定是正数。
如何实现pre?递归中,处理该节点时,如果有pre就计算,没有就记录为pre(此时是最左节点)。
// 中序递归
class Solution {
TreeNode pre; // 记录上一个遍历的结点
int result = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
if (root == null)
return 0;
traversal(root);
return result;
}
public void traversal(TreeNode root) {
if (root == null)
return;
// 左
traversal(root.left);
// 中
if (pre != null) {
result = Math.min(result, root.val - pre.val);
}
pre = root;
// 右
traversal(root.right);
}
}
// 中序迭代
class Solution {
TreeNode pre;
Stack<TreeNode> stack;
public int getMinimumDifference(TreeNode root) {
if (root == null) return 0;
stack = new Stack<>();
TreeNode cur = root;
int result = Integer.MAX_VALUE;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur); // 将访问的节点放进栈
cur = cur.left; // 左
}else {
cur = stack.pop();
if (pre != null) { // 中
result = Math.min(result, cur.val - pre.val);
}
pre = cur;
cur = cur.right; // 右
}
}
return result;
}
}
501.二叉搜索树中的众数(pre指针、结果集)
普通树:遍历了,用map统计频率,把频率排个序,最后取前面高频的元素的集合。
BST:中序是有序的。遍历有序数组的元素出现频率,从头遍历,那么一定是相邻两个元素作比较,然后就把出现频率最高的元素输出就可以了。
如果 频率count 等于 maxCount(最大频率),当然要把这个元素加入到结果集中。
频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集。
class Solution {
public int[] findMode(TreeNode root) {
result = new ArrayList<>();
countMax = 0;
find(root, 0);
return result.stream().mapToInt(Integer::intValue).toArray();
}
private List<Integer> result;
private int countMax;
private TreeNode pre;
private int find(TreeNode node, int count){
if(node==null) return count;
count = find(node.left, count);
if(pre!=null){
if(pre.val == node.val){
count++;
}else{
count=1;
}
}else{
count++;
}
pre = node;
if(count==countMax){
result.add(node.val);
}else if(count > countMax){
result.clear();
result.add(node.val);
countMax = count;
}
count = find(node.right, count);
return count;
}
}
236. 二叉树的最近公共祖先 (回溯、后序)
返回值:返回值是TreeNode * ,那么如果遇到p或者q,就把q或者p返回,返回值不为空,就说明找到了q或者p。
- 告诉我们是否找到节点q或者p
- 返回最近公共节点
终止条件:树为空 || 找到了节点
递归逻辑:一定要后序遍历,才会将结果返回到父亲
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null || root==p || root==q) return root;
// 后序
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left!=null && right!=null) return root;
else if(left!=null && right==null) return left;
else if(right!=null && left==null) return right;
else return null;
}
}