LeetCode 530.二叉搜索树的最小绝对差
题目链接🔗:530.二叉搜索树的最小绝对差
解题思路🤔
遇到在二叉搜索树上求最值、差值之类,把它想成在一个有序数组上求最值,求差值。
本题中,二叉搜索树采用中序遍历,其实就是一个有序数组。就转化为在一个有序数组上求两个数最小差值。
因此,思路为将二叉搜索树转换成有序数组,然后遍历一遍数组,就统计出来最小差值了。
遇到的问题😢
代码实现👨🏻💻
递归法
var getMinimumDifference = function (root) {
let arr = [];
const buildArr = (root) => {
if (root) {
buildArr(root.left);
arr.push(root.val);
buildArr(root.right);
}
}
buildArr(root);
let diff = arr[arr.length - 1];
for (let i = 1; i < arr.length; ++i) {
if (diff > arr[i] - arr[i - 1]) diff = arr[i] - arr[i - 1];
}
return diff;
};
总结📖
LeetCode 501.二叉搜索树中的众数
题目链接🔗:501.二叉搜索树中的众数
解题思路🤔
二叉搜索树中序遍历是有序的,从头遍历有序数组的元素出现频率,就是比较相邻两个元素,输出频率最高的元素。
比较相邻两个元素:设置一个指针cur
指向当前节点,初始化一个指针pre = null
,指向前一个节点。
找到频率最高的元素:代码如下:频率count
大于 maxCount
的时候,更新maxCount
,同时清空结果集(result
数组),因为结果集之前的元素都失效了。
遇到的问题😢
代码实现👨🏻💻
迭代法
var findMode = function(root) {
// 使用中序遍历, 设置出现最大次数初始值为1
let count = 0, maxCount = 1;
let pre = root, res = [];
// 1.确定递归函数及函数参数
const travelTree = function(cur) {
// 2. 确定递归终止条件
if(cur === null) return ;
travelTree(cur.left);
// 3. 单层递归逻辑
if(pre.val === cur.val) count++;
else count = 1;
pre = cur;
if(count === maxCount) res.push(cur.val);
if(count > maxCount) {
res = [];
maxCount = count;
res.push(cur.val);
}
travelTree(cur.right);
}
travelTree(root);
return res;
};
总结📖
LeetCode 236. 二叉树的最近公共祖先
题目链接🔗:236. 二叉树的最近公共祖先
解题思路🤔
找到公共祖先:二叉树自底向上查找 —> 回溯 —> 后序遍历(左右中)
- 判断节点是节点q、p的公共祖先:
-
找到一个节点,发现左子树出现节点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
- 此时如果递归遍历遇到q,就将q返回,遇到p就将p返回,如果左右子树的返回值都不为空,说明此时的中节点,一定是q和p 的最近祖先。
![在这里插入图片描述](https://img-blog.csdnimg.cn/806cfaac63aa4a459bd69904291f75a4.png
- 此时如果递归遍历遇到q,就将q返回,遇到p就将p返回,如果左右子树的返回值都不为空,说明此时的中节点,一定是q和p 的最近祖先。
-
节点本身p( q ),它拥有一个子孙节点q ( p )
- 此时如果递归遍历遇到q,就将q返回,遇到p就将p返回,如果左右子树的返回值都不为空,说明此时的中节点,一定是q和p 的最近祖先。
- 此时如果递归遍历遇到q,就将q返回,遇到p就将p返回,如果左右子树的返回值都不为空,说明此时的中节点,一定是q和p 的最近祖先。
- 递归三部曲:
- 确定递归函数的返回值和参数
- 返回值:返回值不为空,说明找到了p、q
- 参数:
- 确定终止条件
root == q
,或者root == p
,说明找到 q p ,则将其返回- 如果遇到空,返回空
- 确定单层递归的逻辑
在递归函数有返回值的情况下:- 如果要搜索一条边,递归函数返回值不为空的时候,立刻返回
- 如果搜索整个树,直接用一个变量
left
、right
接住返回值,这个left
、right
后续还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。 - 如果
left
和right
都不为空,说明此时root
就是最近公共节点。 - 如果
left
为空,right
不为空,就返回right
,说明目标节点是通过right
返回的,反之依然。 - 如果
left
和right
都为空,则返回left
或者right
都是可以的,也就是返回空。
- 完整流程图:
遇到的问题😢
代码实现👨🏻💻
递归法
var lowestCommonAncestor = function(root, p, q) {
// 使用递归的方法
// 需要从下到上,所以使用后序遍历
// 1. 确定递归的函数
const travelTree = function(root, p, q) {
// 2. 确定递归终止条件
if(root === null || root === p || root === q) return root;
// 3. 确定递归单层逻辑
let left = travelTree(root.left, p, q);
let right = travelTree(root.right, p, q);
if(left !== null && right !== null) return root;
if(left === null) return right;
return left;
}
return travelTree(root, p, q);
};
总结📖
递归法
- 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。
- 在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
- 要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果。