代码随想录算法训练营第二十一天|530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先
530.二叉搜索树的最小绝对差
问题简述:求出二叉搜索树中两个元素的最小差值。
思考:因为二叉搜索树中序遍历顺序从小到大,所以只需要在中序遍历中,每次求出前后两个元素差值,并在过程中保存最小的一个。
算法思路:定义last用来记录上一个结点值,定义min作为最小的差值,对二叉树进行中序遍历,每次遍历计算当前节点值和上一个节点值的差值,更新最小差值,并更新上一个结点值。最后返回最小差值。
class Solution {
//记录上个结点值
int last = Integer.MAX_VALUE;
//记录最小差值
int min = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
if (root == null) return 0;
//中序遍历
getMinimumDifference(root.left);
// 计算当前节点值和上一个节点值的差值,更新最小差值
min = Math.min(min, Math.abs(root.val - last));
//更新上一个结点值
last = root.val;
getMinimumDifference(root.right);
return min;
}
}
501.二叉搜索树中的众数
问题简述:找出二叉搜索树中的众数,且众数可能包含多个。
思考:感觉用map容易些,最后通过了。其实更好可以在遍历中直接找到众数。
map算法思路:将元素遍历,元素值作为key,元素出现的次数作为value,遍历map找出最大的value,最后将最大的value对应的所有key存入数组。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Solution {
//定义map
Map<Integer, Integer> map = new HashMap<>();
public int[] findMode(TreeNode root) {
if (root == null) return new int[0];
findMode(root.left);
//元素值作为key,元素出现的次数作为value
map.put(root.val, map.getOrDefault(root.val, 0) + 1);
findMode(root.right);
int max = 0;
List<Integer> list = new ArrayList<>();
//遍历map
for (Map.Entry<Integer, Integer> entry : map.entrySet()){
if (entry.getValue() > max) max = entry.getValue();
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()){
if (entry.getValue() == max) list.add(entry.getKey());
}
//将list转换为数组
return list.stream().mapToInt(Integer::intValue).toArray();
}
}
改进:定义count记录当前数字出现次数,maxcount记录出现的最大次数。用中序遍历,每次判断当前元素与前一个元素值是否相等,如果相等计数器加一;不相等则重制,每次判断count是否等于最大的maxcount,如果相等则加入list,大于maxcount则将list元素清空,再将当前元素加入list。最后更新前一个结点为当前节点。将转换为数组并返回。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Solution {
//用于记录出现次数
int count = 0;
//记录最大出现次数
int maxcount = 0;
List<Integer> list = new ArrayList<>();
//指向前一个结点
TreeNode pre = null;
public int[] findMode(TreeNode root) {
travel(root);
return list.stream().mapToInt(Integer::intValue).toArray();
}
//中序遍历二叉树
public void travel(TreeNode root){
if (root == null) return;
travel(root.left);
//最开始pre为空
if (pre == null) {
//count变为1
count++;
}else if (pre.val == root.val) {
count++;
//count重新计数
}else if (pre.val != root.val) {
count = 1;
}
//如果重数重复出现,则加入list
if (count == maxcount) list.add(root.val);
//如果出现数量更多的数字,则清空list,更新maxcount
if (count > maxcount){
list.clear();
list.add(root.val);
maxcount = count;
}
//更新前一个结点
pre = root;
travel(root.right);
return;
}
}
236. 二叉树的最近公共祖先
问题简述:找出两个结点的公共祖先,且结点本身也可作为公共祖先。
思考:感觉很难,属于一丁点思路也没有,看了视频差不多懂了,特别是把特殊情况也归类到普通情况了,太巧妙了。
算法思路:进行后续遍历,如果找到结点p或q。返回p或q,否则返回null。如果左右都不为空,则一个含有p一个含有q,返回当前结点,且为公共祖先;如果一个结点存在一个不存在,说明已经找到了一个公共祖先,为结点left或者right。注意如果这个结点本身为公共祖先,则也返回了这个结点,并不需要特殊讨论。最后都没找到则返回null。
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) return null;
if (root == p) return p;
if (root == q) return q;
//后序遍历
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
//如果左右都不为空,则一个含有p一个含有q,返回当前结点,且为公共祖先
if (left != null && right != null) return root;
//如果一个结点存在一个不存在,说明已经找到了一个公共祖先,为结点left(如果这个结点本身为公共祖先,则也返回了这个结点,并不需要特殊讨论)
if (left != null && right == null) return left;
//如果一个结点存在一个不存在,说明已经找到了一个公共祖先,为结点right
if (left == null && right != null) return right;
return null;
}
}
感想
啊啊啊啊啊啊啊啊啊啊