530.二叉搜索树的最小绝对差
方法1、利用二叉排序树的特性
先递归得到一个有序数组,再取数组中差值最小的两个数
方法2、递归遍历过程中,通过双指针在遍历的同时,获得前后两个数值的差,并取最小值。
501.二叉搜索树中的众数
方法1:暴力法
拓展map的entrySet()函数以及hashmap的排序问题
先将entrySet集合变为stream流,再排序(降序),再collect转为list类型。
List<Map.Entry<Integer, Integer>> mapList = map.entrySet().stream()
.sorted((c1, c2) -> c2.getValue().compareTo(c1.getValue()))
.collect(Collectors.toList());
排序规则:
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2)
{
//按照value值,重小到大排序
//return o1.getValue() - o2.getValue();
//按照value值,从大到小排序
//return o2.getValue() - o1.getValue();
//按照value值,用compareTo()方法默认是从小到大排序
return o1.getValue().compareTo(o2.getValue());
}
mapToInt:list使用mapToInt将list.stream流改造成Integer流。
Integer::intValue:调用Integer类中的intValue方法,将Integer对象中的值返回,转换成int类型。
toArray():list最终转为数组。
return list.stream().mapToInt(Integer::intValue).toArray();
方法2:利用二叉搜索树的特性
需要用到count和maxCount两个变量。
maxCount获取最大频率。当count>maxCount时,令maxCount=count,同时刷新结果集,放入当前结点。
if (count > maxCount) { // 如果计数大于最大值
maxCount = count; // 更新最大频率
result.clear(); // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
result.push_back(cur->val);
}
538.把二叉搜索树转换为累加树
利用二叉搜索树的特性。翻转中序遍历,利用双指针pre和cur,进行二叉树的遍历并更新数值。
小结
前一天的98.验证二叉搜索树、今天的530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、538.把二叉搜索树转换为累加树都是相似类型的题目。
同样是用到了双指针,前结点pre以及二叉搜索树的特性。
236. 二叉树的最近公共祖先
后序递归遍历
递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(第八天打卡的113.路径总和ii)
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况是在本题中介绍)
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(第八天打卡的112.路径总和)
情况一:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
情况二:节点本身q,它拥有一个子孙节点p。
情况一和情况二代码实现过程都是一样的。
在实现情况一的逻辑中遇到 q 就返回,不会再向下遍历子结点。
同样情况二中,q结点是p结点的祖先,当遇到祖先q时,可以直接返回祖先。
也可以说,实现情况一的逻辑,顺便包含了情况二这种 q 或者 p 本身就是公共祖先的情况。
接下来就是递归三步走。
1、明确参数和返回值
2、明确终止条件
3、明确单次逻辑
235. 二叉搜索树的最近公共祖先
因为是有序树,所以如果中间节点是q和p的公共祖先,那么中间节点的数值一定是在[p, q]区间的。即 p < 中节点 < q 或者 q < 中节点 < p。
那么只要从上到下去遍历,遇到 cur节点是数值在[p, q]区间中则一定可以说明该节点cur就是q 和 p的公共祖先。 那问题来了,一定是最近公共祖先吗?
如图: 如果从节点5继续向左遍历,那么将错过成为q的祖先, 如果从节点5继续向右遍历则错过成为p的祖先。
所以:当我们从上向下去递归遍历,第一次遇到cur节点的数值在[p, q]区间中,那么cur就是 p和q的最近公共祖先。
701.二叉搜索树中的插入操作
常规的递归题,利用二叉搜索树的有序特性。
450.删除二叉搜索树中的节点
删除二叉搜索树的一个结点,有5种情况
1、没有找到删除结点,返回null/root
2、删除结点3,左右节点都不为空,把该节点的左孩子放入右孩子最左结点的左孩子上,返回该节点右孩子成为新的根节点
3、删除节点的左右结点都为空,直接删除,返回null
4、删除结点的左孩子为空,右孩子不为空,返回右孩子作为新的根节点
5、删除节点的右孩子为空,左孩子不为空,返回左孩子作为新的根节点
普通二叉树的删除方式:
没记,待刷
669. 修剪二叉搜索树
这一块递归有点难想。假设给定[1, 3]区间,在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的,还要考虑节点0的右子树以及节点4的左子树。
如何进行修剪:
1、把小于区间的节点0的右孩子节点2 直接赋给节点3的左孩子(即把节点0从二叉树中移除)
2、把大于区间的节点4的左孩子节点直接赋给节点3的右孩子
如下代码相当于把节点0的右孩子(节点2)返回给上一层:
if (root.val < low) {
TreeNode right = trimBST(root.right, low, high); // 寻找符合区间[low, high]的节点
return right;
}
然后如下代码相当于用节点3的左孩子,把下一层返回的节点0的右孩子(节点2) 接住:
root.left = trimBST(root.left, low, high);
此时就完成了对结点0的移除。
108.将有序数组转换为二叉搜索树
其实就是简单的二分查找,但是因为不熟悉,所以错误百出。
1、递归结束条件不知道该怎么写。(递归结束条件是:left > right)递归到只剩下一个元素时,left与right指针是指向同一个元素的
2、区间定义,是左闭右闭,还是左闭右开有点混乱。(一刷规定左闭右闭[0, nums.length - 1])
但是
如果区间定义的是左闭右开[0, nums.length],递归结束条件就是left >= right
避免记混,按照左闭右闭的情况刷题,左闭右开不要记。