LeetCode 530- 二叉搜索树的最小绝对差
题目链接:力扣
题目描述:给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
解题思路
思路一:
- 中序遍历,然后用数组记录遍历结果,再比对最小值。
思路二:
- 由于二叉搜索树的性质,我们可以使用双指针法。
- 二叉搜索树在中序遍历时,遍历顺序是从大到小,所以最小差值肯定是遍历时两个相邻节点之间产生。所以可以用双指针法,一个指针记录pre一个记录cur,然后来遍历整棵树,记录下最小差值即可。
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;
}
};
总结:
二叉搜索树,优化方法大都是利用其中序遍历有序的性质来的,遇到这种题要往这方面想。
LeetCode 501- 二叉搜索树中的众数
题目链接:力扣
题目描述:给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
假定 BST 满足如下定义:
结点左子树中所含节点的值 小于等于 当前节点的值
结点右子树中所含节点的值 大于等于 当前节点的值
左子树和右子树都是二叉搜索树
解题思路
- 又是二叉搜索树,可以利用二叉搜索树的性质,使用双指针。
- 在中序遍历时,遍历结果是从大到小的,所以两个数相等的情况只可能是遍历相邻节点时出现。所以右可以使用双指针法。就能判断众数。
- 使用一个Count来记录当前的数出现次数,maxCount来记录当前众数的出现次数。当Count<maxCount时Count++(并且还pre->val == cur->val),Count==maxCount时将当前数加入至结果集中;当Count>maxCount时将结果集清空,并更新maxCount=Count,然后将当前的数加入到结果集中去。
class Solution {
private:
int maxCount = 0; // 最大频率
int count = 0; // 统计频率
TreeNode* pre = NULL;
vector<int> result;
void searchBST(TreeNode* cur) {
if (cur == NULL) return ;
searchBST(cur->left); // 左
// 中
if (pre == NULL) { // 第一个节点,出现次数就是1
count = 1;
} else if (pre->val == cur->val) { // 与前一个节点数值相同
count++;
} else { // 与前一个节点数值不同,说明第一次出现设置为1
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<int> findMode(TreeNode* root) {
result.clear();
searchBST(root);
return result;
}
};
总结:
- 自己写的时候不知道只有俩个节点的时候怎么处理,题解中有处理就是将pre==NULL作为第一个节点时的特殊处理,开始没想到。
LeetCode 236- 二叉树的最近公共祖先
题目链接:力扣
题目描述:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先.
解题思路:
思路一(两个栈处理深度优先):
- 我们可以记录二叉树的遍历路径,深度优先遍历,当我们往下遍历时会将前面遍历过的节点记录下来,当遇到目标节点时就返回。栈中保存的就是我们遍历的路径,有相同的祖先的两个节点它们的遍历路径在栈中肯定有相同部分,我们可以依据这个来找到公共祖先(最开始也想到了这个,就是不知道该怎么回溯)。
class Solution {
public:
//函数就是找从根节点到指定节点的路径
bool getPath(TreeNode* root, TreeNode* target, stack<TreeNode*>& path) {
if (root == nullptr) {
return false; // 空节点返回false
}
path.push(root); // 将当前节点入栈
if (root == target) { // 当前节点是目标节点
return true;
}
if (getPath(root->left, target, path)) { // 在左子树中找目标节点,找到直接返回
return true;
}
if (getPath(root->right, target, path)) { // 在右子树中找目标节点,找到直接返回给上一层
return true;
}
path.pop(); // 当左右都没找到,回溯时将当前节点出栈,再去试别的路
return false;
}
// 主函数:找到两个节点的最近公共祖先
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
stack<TreeNode*> path1, path2;
getPath(root, p, path1);
getPath(root, q, path2);
if (path1.empty() || path2.empty()) {
return nullptr;
}
while(path1.size()>path2.size()){
path1.pop();
}
while(path2.size()>path1.size()){
path2.pop();
}
TreeNode* result = nullptr;
while (!path1.empty() && !path2.empty()) {
if (path1.top() == path2.top()) {
result = path1.top();
break;
}
path1.pop();
path2.pop();
}
return result;
}
};
思路二(后序遍历处理):
- 后序遍历的顺序是左右中,我们可以用后序遍历来看两个节点是否有公共祖先
- 首先确定终止条件,当我们遇到空或者是找到了p、q都要返回直接返回root。
- 其次是单层递归逻辑,先左后右,当left和right都找到了,也就是都不为空,我们就可以返回当前的root作为答案,如果左边找到了,就把左边往上返回,右边找到了就把右边往上返回,左右都没有找到就返回NULL。
看看流程图
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;
}
}
};
总结:
- 这题就是先找节点,找到之后一层一层的返回,当两边的返回值都不为空,那就是公共祖先了。用栈的解法的思路最后也挺像的。