Day21打卡! 时长:2h
今日感想:依旧是二叉搜索树的应用和最近公共祖先,第三题有难度的,需要复习。
Leetcode530 二叉搜索树的最小绝对差
第一想法:最小差值也不一定在同一个父子节点中出现,应该还是要遍历计算一下。
讲解后想法:重点还是二叉搜索树是有序的,所以转换成在一个有序数组上求最值或差值。
(见二叉搜索树,多想想中序遍历。)
难点/细节:思维上的转换以及如何记录前后两个节点很重要。
代码:递归法
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);
}
}
Leetcode501 二叉搜索树中的众数
第一想法:又是二叉搜索树,可以考虑一下中序遍历再记录出现次数。
讲解后想法:这道题可以一举两得,即普通二叉树和二叉搜索树的思路都可以考虑。
难点/细节:只需遍历一遍的小技巧,在频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空result结果集数组,因为结果集之前的元素都失效了。
代码:
class Solution {
ArrayList<Integer> resList;
int maxCount;
int count;
TreeNode pre;
public int[] findMode(TreeNode root) {
resList = new ArrayList<>();
maxCount = 0;
count = 0;
pre = null;
findMode1(root);
int[] res = new int[resList.size()];
for (int i = 0; i < resList.size(); i++) {
res[i] = resList.get(i);
}
return res;
}
public void findMode1(TreeNode root) {
if (root == null) {
return;
}
findMode1(root.left);
int rootValue = root.val;
// 计数
if (pre == null || rootValue != pre.val) {
count = 1;
} else {
count++;
}
// 更新结果以及maxCount
if (count > maxCount) {
resList.clear();
resList.add(rootValue);
maxCount = count;
} else if (count == maxCount) {
resList.add(rootValue);
}
pre = root;
findMode1(root.right);
}
}
Leetcode236 二叉树的最近公共祖先
第一想法:这感觉是由下至上的遍历,而且还要保证祖先深度尽可能大。
讲解后想法:后序遍历(左右中)是天然的回溯过程,可以实现自底向上查找。
递归三部曲
1.确定递归函数返回值以及参数
需要返回最近公共节点,可以返回值为TreeNode类,如果遇到p或者q,就把q或者p返回,返回值不为空,就说明找到了q或者p。
2.确定终止条件
遇到空的话,返回空。
如果 root == q,或者 root == p,说明找到 q p ,则将其返回,这个返回值,后面在中节点的处理过程中会用到。
3.确定单层递归逻辑
本题函数有返回值,因为回溯的过程需要递归函数的返回值做判断,但本题我们依然要遍历树的所有节点。
在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。
难点/细节:考验对二叉树,递归和回溯的理解。
求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。
在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果。
代码:
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) { // 若未找到节点 p 或 q
return null;
}else if(left == null && right != null) { // 若找到一个节点
return right;
}else if(left != null && right == null) { // 若找到一个节点
return left;
}else { // 若找到两个节点
return root;
}
}
}