心得:
注意用for遍历数组元素中相邻两个元素的差时,i从1开始就可以一直到size,从0开始则要让i<size - 1.
二叉树没法从下往上遍历,但是可以用回溯来从下往上处理。
递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(112.路径总和)
第一题、二叉搜索树中的最小绝对差 LeetCode530 https://leetcode.cn/problems/minimum-absolute-difference-in-bst/
可以和前一天的最后一题类似,放入数组中然后找出相邻两个数的最小差。
注意用for遍历数组元素中相邻两个元素的差时,i从1开始就可以一直到size,从0开始则要让i<size - 1.
class Solution {
public:
vector<int> vec;
void traversal(TreeNode* node){
if(node == NULL) return;
traversal(node->left);
vec.push_back(node->val);
traversal(node->right);
}
int getMinimumDifference(TreeNode* root) {
int res = INT_MAX;
vec.clear();
traversal(root);
if (vec.size() < 2) return 0;
for(int i = 0; i < vec.size()-1; i++){
int dif = vec[i + 1] - vec[i];
res = min(res, dif);
}
// for(int i = 1; i < vec.size(); i++){
// int dif = vec[i] - vec[i - 1];
// res = min(res, dif);
// }
return res;
}
};
当然也可以不用额外的数组,直接遍历节点然后直接计算。使用双指针法,一个pre指针指向前一个节点。
class Solution {
public:
int res = INT_MAX;
TreeNode* pre = NULL;
void traversal(TreeNode* cur){
if(cur == NULL) return;
traversal(cur->left);
if(pre != NULL){
res = min(res, cur->val - pre->val);
}
pre = cur;//记录前一个节点
traversal(cur->right);
}
int getMinimumDifference(TreeNode* root) {
traversal(root);
return res;
}
};
第二题,二叉搜索树的众数 LeetCode501 https://leetcode.cn/problems/find-mode-in-binary-search-tree/submissions/
思路上是可以用双指针法将整个二叉树遍历一边,再把结果集遍历一遍找出最高频率的数。但通过使用count和maxcount的技巧,可以不用遍历两边。
如果 频率count 等于 maxCount(最大频率),当然要把这个元素加入到结果集中(以下代码为result数组),代码如下:
if (count == maxCount) { // 如果和最大值相同,放进result中
result.push_back(cur->val);
}
为什么result怎么能轻易就把元素放进去了呢?万一,这个maxCount此时还不是真正最大频率呢。
所以下面要做如下操作:
频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集(以下代码为result数组),因为结果集之前的元素都失效了。
if (count > maxCount) { // 如果计数大于最大值
maxCount = count; // 更新最大频率
result.clear(); // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
result.push_back(cur->val);
}
class Solution {
public:
int maxCount = 0;
int count = 0;
TreeNode* pre = NULL;
vector<int> res;
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;
//如果和maxcount相同,则放入结果集
if(count == maxCount) res.push_back(cur->val);
if(count > maxCount){//如果大于最大频率
maxCount = count;//更新最大频率吧
res.clear();//不要忘记把之前的result清空
res.push_back(cur->val);
}
searchBST(cur->right);
return;
}
vector<int> findMode(TreeNode* root) {
count = 0;
maxCount = 0;
TreeNode* pre = NULL;
res.clear();
searchBST(root);
return res;
}
};
第三题、二叉树的最近公共祖先 LeetCode 236https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/
递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(112.路径总和)
就这道题而言,要对left和right的递归值进行处理,所以递归函数就需要按返回值。
left = 递归函数(root->left); // 左
right = 递归函数(root->right); // 右
left与right的逻辑处理; // 中
那么先用left和right接住左子树和右子树的返回值,代码如下:
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
如果left 和 right都不为空,说明此时root就是最近公共节点。这个比较好理解
如果left为空,right不为空,就返回right,说明目标节点是通过right返回的,反之依然。
为什么呢?
如果left 和 right都不为空,说明此时root就是最近公共节点。左右分别和一同为空在下面进行处理。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == p || root == q || root == NULL) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
//如果left 和 right都不为空,说明此时root就是最近公共节点。
if (left != NULL && right != NULL) return root;
if(left == NULL && right == NULL){
return NULL;
}
else if(left != NULL && right == NULL){
return left;
}
else{
return right;
}
}
};