530.二叉搜索树的最小绝对差
思路
和昨天的“验证二叉树”差不多,都是需要保留上一个结点以便于和下一个结点的值进行比较看是否满足条件,详情看Day17。
代码实现
class Solution {
public:
int result=INT_MAX;
TreeNode *pre=nullptr;
int getMinimumDifference(TreeNode* root) {
if(root==nullptr)return 0;
getMinimumDifference(root->left);
if(pre&&(root->val-pre->val)<result)result=root->val-pre->val;
pre=root;
getMinimumDifference(root->right);
return result;
}
};
501.二叉搜索树中的众数
思路
二叉搜索树的遍历方式都差不多,采用中序遍历和双指针方式最为常见。这道题也和二叉搜索树最小绝对值差不多,只不过在它的基础上增加了对众数的判断。
- 传入参数及返回值
不需要返回值,直接用全局变量result即可。只需要传入根节点root指针 - 结束遍历条件
遍历到空节点时向上返回 - 中间结点处理过程
当pre->val=cur->val时count++。如果此时count=maxCount则把元素push进数组;如果count>maxCount则清空数组,最后加入众数元素
注意:众数的判断应先判断count=maxCount,不然在更新了maxCount之后,又会重新判断一次是否等于count=maxCount;或者用else if也可以
代码实现
class Solution {
public:
TreeNode* pre=nullptr;
int count=1;
int maxCount=INT_MIN;
vector<int> result;
void traversal(TreeNode *root){
if(root==nullptr)return ;
traversal(root->left);
if(pre&&pre->val==root->val){
count++;
}
else count=1;
pre=root;
if(count==maxCount)result.push_back(root->val);
else if(count>maxCount){
maxCount=count;
while(!result.empty())result.pop_back();
result.push_back(root->val);
}
traversal(root->right);
return ;
}
vector<int> findMode(TreeNode* root) {
traversal(root);
return result;
}
};
如果不是二叉搜索树怎么写
用map来保存元素的key和个数value,然后把它按大顶堆排序,再把元素出现频率最大的放入数组,历遍map中元素看是否有和数组中元素频率一样的。
排序函数
sort(vec.begin( ),vec.end( ),cmp)
cmp(const pair<int,int> &a,const pair<int,int> &b){
return a.second>b.second;//大顶堆
}
class Solution {
private:
void searchBST(TreeNode* cur, unordered_map<int, int>& map) { // 前序遍历
if (cur == NULL) return ;
map[cur->val]++; // 统计元素频率
searchBST(cur->left, map);
searchBST(cur->right, map);
return ;
}
bool static cmp (const pair<int, int>& a, const pair<int, int>& b) {
return a.second > b.second;
}
public:
vector<int> findMode(TreeNode* root) {
unordered_map<int, int> map; // key:元素,value:出现频率
vector<int> result;
if (root == NULL) return result;
searchBST(root, map);
vector<pair<int, int>> vec(map.begin(), map.end());
sort(vec.begin(), vec.end(), cmp); // 给频率排个序
result.push_back(vec[0].first);
for (int i = 1; i < vec.size(); i++) {
// 取最高的放到result数组中
if (vec[i].second == vec[0].second) result.push_back(vec[i].first);
else break;
}
return result;
}
};
236. 二叉树的最近公共祖先
思路
本题有两种情况:
1.p和q分别为某结点的左右子孙;
2.p和q有一个为祖先结点一个为子结点
但不管是那种情况都可以通过后序遍历返回的已知的左右孩子结点来解决。在如下代码的后序遍历中,如果想利用left和right做逻辑处理, 不能立刻返回,而是要等left与right逻辑处理完之后才能返回,所以利用后序遍历最方便,递归方法如下:
- 递归终止条件
当遇到空节点则证明本条路径没有结点等于p或q则直接返回空节点;当结点等于p或q,直接返回当前节点 - 递归返回方法
递归返回的值应使用一个容器接收,分别为left和right,用来判断是否找到了p和q结点。
如果left 和 right都不为空,说明此时root就是最近公共节点。如果left为空,right不为空,就返回right,说明目标节点是通过right返回的,反之依然
代码实现
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==NULL)return NULL;
if(root==p||root==q)return root;
TreeNode *left=lowestCommonAncestor(root->left,p,q);
TreeNode *right=lowestCommonAncestor(root->right,p,q);
if(left&&right)return root;
else if(left&&right==NULL)return left;
else if(right&&left==NULL)return right;
else return NULL;
}
};
总结
- 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。
- 在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
- 要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果