代码随想录算法训练营
Day18 代码随想录算法训练营第 18 天 |LeetCode 530.二叉搜索树的最小绝对差 LeetCode501.二叉搜索树中的众数 LeetCode236. 二叉树的最近公共祖先
目录
前言
LeetCode530.二叉搜索树的最小绝对差
LeetCode501.二叉搜索树中的众数
LeetCode236. 二叉树的最近公共祖先
一、基础
最近公共祖先:对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)
二、LeetCode 530.二叉搜索树的最小绝对差
1.题目链接
2.思路
(1)利用二叉搜索树的有序性:中序遍历获取有序数组
(2)遍历数组:中序数组是升序,ans[i]-ans[i-1]一定是正的,遍历,取最大值
3.题解
class Solution {
public:
void inorder(TreeNode* node, vector<int>& ans) {
if (node == NULL)
return;
inorder(node->left, ans);
ans.push_back(node->val);
inorder(node->right, ans);
}
int getMinimumDifference(TreeNode* root) {
vector<int> ans;
inorder(root, ans);
int n = ans.size();
int res = 1000000;
for (int i = 1; i < n; i++) {
res = min(res, ans[i] - ans[i - 1]);
}
return res;
}
};
三、LeetCode501.二叉搜索树中的众数
1.题目链接
2.思路
(1)求频率:将元素放进map的键,频数放进map的值
(2)求众数需要对频数排序,但是map的排序只能是对键排序
所以要把map放进<int,int>类型的数组,进行排序
(注意排序是需要自定义排序函数
3.题解
class Solution {
public:
void inorder(TreeNode* node, map<int, int>& m) {
if (node == NULL)
return;
inorder(node->left, m);
m[node->val]++;
inorder(node->right, m);
}
bool static cmp(pair<int, int> a, pair<int, int> b) {
return a.second > b.second;
}
vector<int> findMode(TreeNode* root) {
vector<int> res;
map<int, int> m;
if (root == NULL)
return res;
inorder(root, m);
vector<pair<int, int>> frequency(m.begin(), m.end());
sort(frequency.begin(), frequency.end(), cmp);
int max_num = frequency[0].second;
res.push_back(frequency[0].first);
for (int i = 1; i < frequency.size(); i++) {
if (frequency[i].second == max_num)
res.push_back(frequency[i].first);
else
break;
}
return res;
}
};
四、LeetCode236. 二叉树的最近公共祖先
1.题目链接
2.思路
(1)最近公共祖先:
对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)
(2)遍历方式:后序
判定最近公共祖先首先要找到p和q,所以需要回溯(自底向上)
(3)最近公共祖先的判定:
如果遍历到p则返回p,如果遍历到q则返回q,检测左右返回值是否为空,如果都不为空,那么中间节点就是最近公共祖先
(4)递归实现
1)参数和返回值
2)边界条件:如果遍历到p,q,空指针,则返回
3)单层递归:
因为需要保存递归函数的返回值进行后续判断,所以采用遍历一整颗树的写法;
若left和right均不为空:返回Root为最近公共祖先
若left为空right不为空:所求的最近公共祖先是从right返回的,所以返回right
若right为空left不为空:所求的最近公共祖先是从left返回的,所以返回left
若均为空:返回NULL
若left为空right不为空:所求的最近公共祖先是从right返回的,所以返回right
若right为空left不为空:所求的最近公共祖先是从left返回的,所以返回left
这一段为了便于理解,可以参考下面的图
回溯过程
3.题解
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==p||root==q||root==NULL)return root;
TreeNode * l=lowestCommonAncestor(root->left,p,q);
TreeNode* r=lowestCommonAncestor(root->right,p,q);
if(l!=NULL && r!=NULL)return root;
else if( l!=NULL && r==NULL) return l;
else if(l==NULL && r!=NULL)return r;
else return NULL;
}
};
总结
今天的二叉树最近公共祖先是难点
1.二叉树最近公共祖先的总结:
1)使用后序遍历
2)回溯过程用遍历整个树的写法:因为需要保存递归函数的返回值用于判断
3)若left为空right不为空:所求的最近公共祖先是从right返回的,所以返回right
2.遍历顺序的选择
如果利用二叉搜索树的有序性,用中序遍历
求最近公共祖先:用后序遍历