530.二叉搜索树的最小绝对差
题目链接:530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)
文章链接:代码随想录 (programmercarl.com)
视频链接:二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差
当我们充分了解了二叉搜索树的性质后,这道题就十分简单了。
我们可以将二叉树通过中序递归组成一个数组,由于二叉搜索树的性质,这是一个递增的数组,然后只要通过一次遍历,就能找到两个数的最小差值了。
代码如下:
class Solution {
public:
vector<int> vec;
void traversal(TreeNode* root){//构建数组
if(root==NULL) return;
traversal(root->left);
vec.push_back(root->val);
traversal(root->right);
}
int getMinimumDifference(TreeNode* root) {
traversal(root);
int result=INT_MAX;
if(vec.size()<2){
return 0;
}
for(int i=1;i<vec.size();i++){//遍历
if(vec[i]-vec[i-1]<result){
result=vec[i]-vec[i-1];
}
}
return result;
}
};
当然,这道题也可以不使用构建升序数组的方法,而是才用双指针法,一个指针root指向当前节点,另一个指针pre只向上一次递归所在的节点,然后用root->val-pre->val,其实与构建数组相比,思路时一样的,由于还是采用的中序递归,所以其实两个指针就相当于数组中的vec[i]、vec[i-1],只是省去了建立新数组的步骤,代码如下:
class Solution {
public:
int result=INT_MAX;
TreeNode* pre=NULL;
void traversal(TreeNode* root)
{
if(root==NULL) return;
traversal(root->left);
if(pre!=NULL){
result=min(result,root->val-pre->val);
}
pre=root;
traversal(root->right);
}
int getMinimumDifference(TreeNode* root) {
traversal(root);
return result;
}
};
501.二叉搜索树中的众数
题目链接:501. 二叉搜索树中的众数 - 力扣(LeetCode)
文章链接:代码随想录 (programmercarl.com)
视频链接:不仅双指针,还有代码技巧可以惊艳到你! | LeetCode:501.二叉搜索树中的众数
这道题我的第一想法就是管他是二叉什么树,直接无脑遍历一遍,然后用map记录元素出现次数就可以了。
class Solution {
public:
void traversal(TreeNode* root,unordered_map<int,int> &map)//遍历,放入map中
{
if(root==NULL) return;
map[root->val]++;
traversal(root->left,map);
traversal(root->right,map);
}
bool static cmp(const pair<int,int>&a,const pair<int,int>&b)//自定义排序顺序
{
return a.second>b.second;
}
vector<int> findMode(TreeNode* root) {
unordered_map<int,int> map;
traversal(root,map);
vector<int> result;
vector<pair<int,int>> vec(map.begin(),map.end());//将map放入二维数组中
sort(vec.begin(),vec.end(),cmp);//将数组排序
result.push_back(vec[0].first);//先存第一个
for(int i=1;i<vec.size();i++)
{
if(vec[i].second==vec[0].second){
result.push_back(vec[i].first);只要后面的个数和第一个相等,就再加进result中
}
else break;
}
return result;
}
};
当然,我们也可以靠二叉搜索树的性质——父节点和它的左右子节点可能相等,所以我们也可以使用双指针法,如上题,pre记录上一个节点,root记录当前节点,只要相等那么count++,并把元素放进result数组中,如果不相等,就重置count,继续递归,并用maxcount记录递归过程中最大的count,如果出现更大的count就清空result,放入新的元素。
代码如下:
class Solution {
public:
TreeNode* pre=NULL;
int count=0;
int maxcount=0;//记录递归中最大的count
vector<int> result;//记录结果
void traversal(TreeNode* root)//中序递归
{
if(root==NULL) return;
traversal(root->left);
if(pre==NULL) count=1;//说明到达叶子节点,这是第一个数
else if(root->val==pre->val) count++;
else count=1;
pre=root;
if(count==maxcount) result.push_back(root->val);//有相同频率的数字,就加入数组中
if(count>maxcount){//有更高频率的数字,就重置数组
maxcount=count;
result.clear();
result.push_back(root->val);
}
traversal(root->right);
return;
}
vector<int> findMode(TreeNode* root) {
traversal(root);
return result;
}
};
二叉树的最近公共祖先
题目链接:236. 二叉树的最近公共祖先 - 力扣(LeetCode)
文章链接:代码随想录 (programmercarl.com)
视频链接:自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先
这道题稍微难了点,求最近公共祖先,我们就要从底部向上遍历,所以只能用后续递归来解决。而由于这是一个递归回溯的过程,我们如果找到了p、q还需要不断地向上返回他们的节点就相当于将p、q节点不断向上传递的过程(可能有点抽象......)。代码如下:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==NULL||root==p||root==q) return root;
TreeNode* left=lowestCommonAncestor(root->left,p,q);
TreeNode* right=lowestCommonAncestor(root->right,p,q);
if(left!=NULL&&right!=NULL) return root;//如果左右孩子都不为NULL,说明root就是共同祖先
else if(left!=NULL&&right==NULL) return left;//如果一边有右边无,有两种情况,第一种指遍历到p或者q,正在返回该节点,第二种情况就是已经找到共同祖先,正在向上返回祖先的节点,
else if(left==NULL&&right!=NULL) return right;
else return NULL;
}
};
其实还包括了一种情况,p是q的公共祖先或q是p的公共祖先,这种情况其实隐含在上面的代码里了,假如p是q的公共祖先,我们通过递归,递归到了p,就直接通过
if(root==NULL||root==p||root==q) return root;这一串代码返回了,p后面的节点q自然就遍历不到了,直接返回q节点了。
Day21 打卡成功,耗时3小时再接再厉。