思路:
这题求的是二叉搜索树的最小绝对值差,我们可以把二叉搜索树看成一个有序数组,一个有序数组上求最小决定值差值岂不是很简单。
思路1.我们最先想到的思路无非是利用中序遍历,将二叉搜索树的节点一个一个放到数组当中,然后求出数组里面的最小绝对值差值。(这个很简单,不解释
思路2.我们可以利用定义一个pre指针(初始化为null),pre指针每次指向当前节点的前一个结点,再定义一个全局变量用于存储最小差值,利用中序遍历二叉搜索树,每次都用当前结点的值减去前一个结点的值,让他与最小差值比较,取出最小值,中序遍历结束后就可以得到最小差值。
class Solution {
private:
int result = INT_MAX;
TreeNode* pre = NULL;
void traversal(TreeNode* cur) {
if (cur == NULL) return;
traversal(cur->left); // 左
if (pre != NULL){ // 中
result = min(result, cur->val - pre->val);
}
pre = cur; // 记录前一个
traversal(cur->right); // 右
}
public:
int getMinimumDifference(TreeNode* root) {
traversal(root);
return result;
}
};
相应的迭代法就是模仿递归操作
思路:
求二叉搜索树的众数,有一个难点就在于这个众数可能不止,所以不能只用一个变量用于存储众数,而是要用一个数组来存储众数。
方法1:如果这是一个普通的二叉树,那么我们可以使用一个map来通过遍历将二叉树结点的值和出现的次数存起来,然后因为不能在map里面直接按照value进行排序,所以我们将创建一个vector
方法2:通过利用搜索二叉树的特性,利用中序遍历搜索二叉树,就相当于一个有序数组,如果在有序数组上找出现频率最高的数字是不是较为简单?同样这题我们定义几个全局变量,首先是pre指针(初始化为null)指向当前遍历元素的上个元素,vector
代码展示:
class Solution {
private:
int maxCount = 0; // 最大频率
int count = 0; // 统计频率
TreeNode* pre = NULL;
vector result;
void searchBST(TreeNode* cur) {
if (cur == NULL) return ;
searchBST(cur->left); // 左
// 中
if (pre == NULL) { // 第一个节点
count = 1;
} else if (pre->val == cur->val) { // 与前一个节点数值相同
count++;
} else { // 与前一个节点数值不同
count = 1;
}
pre = cur; // 更新上一个节点
if (count == maxCount) { // 如果和最大值相同,放进result中
result.push_back(cur->val);
}
if (count > maxCount) { // 如果计数大于最大值频率
maxCount = count; // 更新最大频率
result.clear(); // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
result.push_back(cur->val);
}
searchBST(cur->right); // 右
return ;
}
public:
vector findMode(TreeNode* root) {
count = 0;
maxCount = 0;
TreeNode* pre = NULL; // 记录前一个节点
result.clear();
searchBST(root);
return result;
}
};
思路:
遇到这个题目首先想到的是要是自底向上查找就好了,这样就可以找到公共祖先了。
那么二叉树如何自底向上查找?回溯,二叉树回溯的过程就是自底向上。
后序遍历是天然的回溯过程,最先处理的就是叶子结点。
接下来就看如何判断一个结点是节点q和结点p的公共祖先结点呢。
使用后序遍历,回溯的过程,就是从低向上遍历结点,一旦发现满足第一种情况的节点,就是最近公共结点了。
其实只需要找到一个节点p或者q的时候,直接返回当前节点,无需继续递归子树。
如果接下来的遍历中找到了后继节点满足第一种情况则修改返回值为后继节点,否则,继续返回已找到的节点即可。
递归三部曲:
1.确定参数和返回值:
需要递归函数返回值,来告诉我们是否找到节点P或者q,那么返回bool就行。
但我们还要返回最近公共节点,可以利用上题目中返回值为TreeNode* ,那么如果遇到p或者q,就把p或者q返回,返回值不为空,说明找到了p或者q.
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
2.确定终止条件
如果找到了节点p或者q,或者遇到空节点,就返回。
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
3.确定单层逻辑:
值得注意的是 本题函数有返回值,是因为回溯过程需要递归函数的返回值做判断,但本题我们依然要遍历树的所有节点。之前我们遇到的有返回值的是只需要遍历某一条边的,但是这题却要遍历整个二叉树,那是因为这题虽然有返回值,但是也要看我们如何处理返回值,这题如果像遍历一条边那样,遍历到p或者q就直接返回,那么将会错过前面分析的第一种情况。
如果递归函数有返回值,如果区分要搜索一条边,还是搜索整个数呢?
搜索一条边的写法:
if (递归函数(root->left)) return ;
if (递归函数(root->right)) return ;
搜索整个树写法:
left = 递归函数(root->left);
right = 递归函数(root->right);
left与right的逻辑处理;
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == q || root == p || root == NULL) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left != NULL && right != NULL) return root;
if (left == NULL && right != NULL) return right;
else if (left != NULL && right == NULL) return left;
else { // (left == NULL && right == NULL)
return NULL;
}
}
};