参考链接:代码随想录
思路:我一开始想到的方法是先生成中序序列,然后对相邻两项的差进行计算,取最小值,时间复杂度O(n)。
class Solution {
public:
vector<int> inorder;
void traverse(TreeNode* root){
if(!root){
return;
}
traverse(root->left);
inorder.push_back(root->val);
traverse(root->right);
}
int getMinimumDifference(TreeNode* root) {
traverse(root);
//节点范围从2开始
int min=INT_MAX;
for(int i=1;i<inorder.size();i++){
if(inorder[i]-inorder[i-1]<min){
min=inorder[i]-inorder[i-1];
}
}
return min;
}
};
然后想想能不能直接迭代,即每次遍历的时候记录前置节点,然后将差值对比。
class Solution {
public:
TreeNode* pre=nullptr;
int getMinimumDifference(TreeNode* root) {
if(!root){
return INT_MAX;//指示最小差值不存在
}
int left=getMinimumDifference(root->left);
int min=left;//首先设置为左子树算出的结果
if(pre&&root->val-pre->val<left){
min=root->val-pre->val;
}
pre=root;//赋值前置节点,然后继续往后遍历
int right=getMinimumDifference(root->right);
if(right<min){//完成了左右中的比较
min=right;
}
return min;
}
};
实际上这样写代码很容易出错,真正写的时候就可以用额外生成的vector。标答把答案当做全局变量了,我们也建议单独写一个void遍历函数。
标答:
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;
}
};
迭代法pass。
思路:简单的想法就是生成中序数组,然后使用哈希表统计元素出现个数,然后再输出。但是会有很多额外空间。其实这个方法对不是BST也可以,就是记录所有元素个数。时间复杂度O(n)。
class Solution {
public:
unordered_map<int,int> mp;
void traverse(TreeNode* root){
if(!root){
return;
}
traverse(root->left);
mp[root->val]++;
traverse(root->right);
}
vector<int> findMode(TreeNode* root) {
vector<int> ans;
int max=0;
traverse(root);
for(auto it:mp){
if(it.second>max){
max=it.second;
}
}
for(auto it:mp){
if(it.second==max){
ans.push_back(it.first);
}
}
return ans;
}
};
标答将map进行了一个转换为vector后排序,我觉得没必要,这样复杂度反而变成O(nlogn)。
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;
}
};
考虑一下能不能利用BST的性质。即中序遍历有序,可以直接再遍历过程中操作,和上一题一样,不需要使用额外空间,使用pre指针,在对每个节点遍历的时候记录其出现次数,遍历一遍即可记录最大次数,然后第二次遍历,对最大次数的节点进行输出即为结果。看完解析发现可以通过一些简单的代码操作只进行一次遍历,即每次进行次数更新的时候,将结果clear()即可。可以看到对BST,利用其有序性,双指针有很大用处。
class Solution {
public:
TreeNode* pre=nullptr;
int count=0;
int maxCount=INT_MIN;
void traverse(TreeNode* root,vector<int>& ans){
if(!root){
return;
}
traverse(root->left,ans);
if(!pre||root->val!=pre->val){//第一个元素,指针为空,或者当前和pre不同
count=1;
}
else{//两个相邻相等
count++;
}
pre=root;
//此时已经完成count计数,然后和max比较
if(count>maxCount){
ans.clear();//更新,之前全部删掉
maxCount=count;
ans.push_back(root->val);
}
else if(count==maxCount){//等于也要增加结果
ans.push_back(root->val);
}
traverse(root->right,ans);
}
vector<int> findMode(TreeNode* root) {
vector<int> ans;
traverse(root,ans);
return ans;
}
};
迭代法pass
思路:由于二叉树无法自底向上搜索,肯定需要回溯法。给定pq,需要分情况讨论。首先是简单情况,一个节点的两个孩子分别为p和q,这时候直接返回p或者q,如果为空,则返回空。我们需要把返回值一层一层往上传递,对根节点root,如果左右孩子都为空,则返回空,如果两个节点仅有一个找到了 ,则直接把这一个往上传递,如果两个都不为空,那么这个节点就是最近公共祖先,直接往上返回,最后的返回结果会传递到根节点。本题需要先处理左右孩子,最后确定根节点的返回值,为后序遍历。时间复杂度O(n)。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root||root==p||root==q){//终止条件,表示找到
return root;
}
TreeNode* left=lowestCommonAncestor(root->left,p,q);
TreeNode* right=lowestCommonAncestor(root->right,p,q);
if(!left&&!right){//处理完左右后四种情况
return nullptr;
}
else if(left&&!right){
return left;
}
else if(!left&&right){
return right;
}
else{
return root;
}
}
};
没有迭代法。