二叉搜索树的最小绝对差
题目链接: 力扣
这题首先可以利用二叉搜索树的后序遍历是升序数组来求最小绝对值差 ,解法如下:
int getMinimumDifference(TreeNode* root) {
vector<int> Nodeval;
traverse(root,Nodeval);
int res = INT_MAX;
for(int i=0; i<Nodeval.size()-1;i++)
{
if(Nodeval[i+1] != Nodeval[i])
res = min(res, Nodeval[i+1]-Nodeval[i]);
}
return res;
}
void traverse(TreeNode* cur, vector<int>& Nodeval) //对于BST,中序遍历结果是升序的
{
if(!cur) return;
if(cur->left) traverse(cur->left,Nodeval);
Nodeval.push_back(cur->val);
if(cur->right) traverse(cur->right,Nodeval);
}
其实在二叉搜索树中序遍历的过程中,就可以直接进行计算,而不用再转化为有序数组。
这种方法需要一个pre节点记录cur节点的前一个节点。其中这种解法的实质就是双指针。
int result=INT_MAX;
TreeNode* pre = NULL;
void traverse(TreeNode* cur)
{
if (!cur) return;
traverse(cur->left);
if(pre != NULL)
result = min(result, cur->val - pre->val);
pre = cur;
traverse(cur->right);
}
int getMinimumDifference(TreeNode* root)
{
traverse(root);
return result;
}
二叉搜索树中的众数
题目链接:力扣
这题的解法和上题类似。
如果是利用搜索二叉树后序遍历的性质,解法如下:
将整棵树后序遍历,用map统计频率;再在map中找出最大频率;再取高频元素
class Solution {
public:
vector<int> findMode(TreeNode* root) {
unordered_map<int,int> MyMap;
vector<int> res;
traverse(root, MyMap);
int tempmax=INT_MIN;
for(auto i = MyMap.begin(); i != MyMap.end(); i++)
tempmax = max(tempmax, i->second);
for(auto i = MyMap.begin(); i != MyMap.end(); i++)
{
if(i->second == tempmax)
res.push_back(i->first);
}
return res;
}
void traverse(TreeNode* cur, unordered_map<int,int>& MyMap)
{
if (!cur) return;
if(cur->left) traverse(cur->left, MyMap);
MyMap[cur->val]++;
if(cur->right) traverse(cur->right, MyMap);
}
};
双指针的写法:
一个指针指向前一个节点,这样每次cur(当前节点)才能和pre(前一个节点)作比较。
而且初始化的时候pre = NULL,这样当pre为NULL时候,我们就知道这是比较的第一个元素,设count = 1; 当cur值与pre值相等时,count++,否则,count重新回到1.
if (pre == NULL) { // 第一个节点
count = 1; // 频率为1
} else if (pre->val == cur->val) { // 与前一个节点数值相同
count++;
} else { // 与前一个节点数值不同
count = 1;
}
pre = cur; // 更新上一个节点
按照常规方法,需要遍历两次二叉搜索树,第一次用于找出最大频率,第二次把寻找最大频率的元素并放入集合。
当然,有技巧可以避免遍历两遍二叉搜索树 。
如果 频率count 等于 maxCount(最大频率),要把这个元素加入到结果集中,
这个maxCount此时还不是真正最大频率,
频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集,因为结果集之前的元素都失效了。
关键代码如下所示:
if (count == maxCount) { // 如果和最大值相同,放进result中
result.push_back(cur->val);
}
if (count > maxCount) { // 如果计数大于最大值频率
maxCount = count; // 更新最大频率
result.clear(); // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
result.push_back(cur->val);
}
完整代码如下所示:
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) { // 第一个节点
count = 1;
} else if (pre->val == cur->val) { // 与前一个节点数值相同
count++;
} else { // 与前一个节点数值不同
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) {
count = 0;
maxCount = 0;
TreeNode* pre = NULL; // 记录前一个节点
result.clear();
searchBST(root);
return result;
}
};
二叉树的最近公共祖先
题目链接:力扣
后序遍历(左右中)就是天然的回溯过程,可以根据左右子树的返回值,来处理中节点的逻辑。
如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
判断逻辑是 如果递归遍历遇到q,就将q返回,遇到p 就将p返回,那么如果 左右子树的返回值都不为空,说明此时的中节点,一定是q 和p 的最近祖先。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == p || root == q || !root ) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q); //左
TreeNode* right = lowestCommonAncestor(root->right, p, q); //右
if(left && right) return root;
if(!left && right) return right;
else if(left && !right) return left;
else return NULL;
}
};