非科班学习算法day19 | LeetCode530:二叉搜索树的最小绝对差 ,Leetcode501:二叉搜索树的众数 ,Leetcode236:二叉树的最近公共祖先
目录
介绍
包含LC的两道题目,还有相应概念的补充。
相关图解和更多版本:
代码随想录 (programmercarl.com)https://programmercarl.com/#%E6%9C%AC%E7%AB%99%E8%83%8C%E6%99%AF
一、LeetCode题目
1.LeetCode530:二叉搜索树的最小绝对差
题目链接:530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)
题目解析
首先要知道,最小绝对差会出现在什么位置,因为限定了任意两个数的差值,但根据二叉搜索树的特点,如果用相隔远的两个数相减,差值一定大于相邻两数,所以问题退化到中序遍历相邻两数计算最小差值。
可以采用设置临时指针pre来一遍遍历就完成。
或者直观的方法,中序遍历记录元素信息,将得到的数组进行遍历。
c++代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left),
* right(right) {}
* };
*/
class Solution {
public:
// 需要中序遍历,最小差出现在前后两个数中间,所以可以设置临时指针
// 创建临时指针
TreeNode* pre = nullptr;
// 创建最大值
int min_dif = INT_MAX;
// 中序遍历函数
void dis(TreeNode* root) {
if (!root)
return;
// 左
dis(root->left);
// 处理
if (pre) {
int cur_dif = abs(pre->val - root->val);
min_dif = min(min_dif, cur_dif);
}
pre = root;
dis(root->right);
return;
}
int getMinimumDifference(TreeNode* root) {
dis(root);
return min_dif;
}
};
比较直观的c++代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left),
* right(right) {}
* };
*/
class Solution {
public:
void dis(TreeNode* root, vector<int>& vec) {
if (!root)
return;
dis(root->left, vec);
vec.push_back(root->val);
dis(root->right, vec);
return;
}
int getMinimumDifference(TreeNode* root) {
vector<int> result;
dis(root, result);
int min_num = INT_MAX;
for (int i = 0; i < result.size() - 1; ++i) {
min_num = min(min_num, result[i + 1] - result[i]);
}
return min_num;
}
};
2.Leetcode501: 二叉搜索树的众数
题目链接:501. 二叉搜索树中的众数 - 力扣(LeetCode)
题目解析
个人认为很喜欢的一道题目,我遵循的也是双指针思想:中序遍历,实时更新最大长度,然后将最大长度对应的结果放到返回数组中,但是遇到了问题:
1.最大初始长度设置为0,这样一开始的根节点怎么处理,因为实际上最小的长度应该是1
2.在一次遍历的过程中,如果发现最大值就记录,其实不能保证这是全过程的最大长度(后面的可能会有更长的),那么弹出的条件怎么设置。
C++代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left),
* right(right) {}
* };
*/
class Solution {
public:
// 设置前一指针
TreeNode* pre = nullptr;
// 设置最大长度
int max_len = 0;
// 设置当前长度
int len = 0;
vector<int> res;
void dis(TreeNode* root) {
if (!root)
return;
dis(root->left);
if (!pre)
len = 1;
else if (pre->val == root->val) {
len++;
} else
len = 1;
if (len == max_len) {
res.push_back(root->val);
}
if (len > max_len) {
max_len = len;
res.clear();
res.push_back(root->val);
}
pre = root;
dis(root->right);
return;
}
vector<int> findMode(TreeNode* root) {
max_len = 0;
len = 0;
res.clear();
pre = nullptr;
dis(root);
return res;
}
};
关于这两个问题:1.pre指针还指向空的时候就把指针设置为1,注意在长度没有增加时候else情况,要把长度重置为1,这点很重要。其实我认为也可以直接初始化就设置为1;
2.没有必要弹出,因为如果后面搜索到更长的长度,我们只需要清空当前结果就可以了,前面的结果都不是想要的。
3.Leetcode236:二叉树的最近公共祖先
题目链接:236. 二叉树的最近公共祖先 - 力扣(LeetCode)
题目解析
一开始理解的很艰难,因为涉及到类似于从底部向上检索的过程,这里面是一定有回溯。首先纠正一个问题,就是我在尝试用bool的返回类型辅助函数,但是我写的过程中发现我无法用这个函数来记录或者说返回节点信息,除非是用pair来记录存在信息和节点信息,那样理解是相对好了,但是写法上复杂度大大增加。
现在的写法的关键就是,还是后序遍历的模板,但是在回溯过程中(就是return!)当不存在我们需要检索的值时候,返回空指针,这样也可以帮助我们bool判断!
标记一下,相关的有需要下向上搜索的题目,后期再比对总结:树的最大深度/最小深度,树的直径,路径总和问题
C++代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (!root)
return NULL;
if (root->val == p->val || root->val == q->val)
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;
if (left && !right)
return left;
else
return NULL;
}
};
注意点1:代码虽然看起来简单,但是这个中止条件之所以没有放在后面是因为,遵循的逻辑是先向下搜索,搜索到需要值,返回这个节点信息到上一层,这样就记录了节点信息。
而后面的处理是针对于一层递归左右结束之后中节点的处理逻辑,两者是不一样的,不要混淆。
总结
补打卡第19天,坚持!!!