题目:530.二叉搜索树的最小绝对差
尝试解答:遇到疑问:除了最左下角和最右下角的节点,其他底部节点需要判断终止条件吗
大体思路是有点:min记录当前最小值,双指针,pre记录前一个节点,做中序遍历,中的处理为比较min和root->val - pre->val的大小。
问题就是不知到最左下角和最右下角怎么办?
解决办法:重新写一个无返回值的函数
class Solution {
public:
int min = INT_MAX;
TreeNode *pre = NULL;
void traversal(TreeNode *node){
if(node == NULL) return;
traversal(node->left); //左
if(pre != NULL && node->val - pre->val < min){ //重新写一个函数,就可以在此处排除掉最左下角的特殊情况
min = node->val - pre->val; //中
}
pre = node;
traversal(node->right); //右
}
int getMinimumDifference(TreeNode* root) {
traversal(root);
return min;
}
};
题目:501.二叉搜索树中的众数
尝试解答:思路和答案讲的一模一样,自己也能写出自以为理想的代码,可是运行时出不了结果。
思路:中序遍历,只做一次循环。
一边遍历一遍用count统计该值出现的次数,然后与maxcount 作比较,判断是否更新result里的数据。
class Solution {
public:
int maxcount = INT_MIN;
int count = 1;
TreeNode *pre = NULL;
vector<int> result;
void traversal(TreeNode *node){
if(node == NULL) return;
traversal(node->left);
if(pre != NULL){
if(node->val == pre->val){
count++;
if(count == maxcount){
result.push_back(node->val);
}
if(count > maxcount){
maxcount = count;
result.clear();
result.push_back(node->val);
}
}else{
count = 1;
}
}
pre = node;
}
vector<int> findMode(TreeNode* root) {
traversal(root);
return result;
}
};
修改之后的代码如下
class Solution {
public:
int maxcount = 0;
int count = 1;
TreeNode *pre = NULL;
vector<int> result;
void searchBST(TreeNode *node){
if(node == NULL) return;
searchBST(node->left);
if(pre != NULL){
if(node->val == pre->val){
count++;
}else{
count = 1;
}
}
pre = node;
if(count == maxcount){
result.push_back(node->val);
}
if(count > maxcount){
maxcount = count;
result.clear();
result.push_back(node->val);
}
searchBST(node->right);
return;
}
vector<int> findMode(TreeNode* root) {
searchBST(root);
return result;
}
};
对比起来显然可看出第一份代码错在了哪里:
if(count == maxcount){
result.push_back(node->val);
}
if(count > maxcount){
maxcount = count;
result.clear();
result.push_back(node->val);
}
在第一份代码里,这一部分代码是在 if(node->val == pre->val)条件之下的,但如果在测试集中maxcount = 1,说明众数出现的次数就是一,此时你就啥也不会返回了
题目:236.二叉树的最近公共祖先(难,还需要理解)
懵了!
需要自底向上查找,就可以找到公共祖先了。那么如何可以自底向上查找呢?
通过回溯,二叉树回溯就是自底向上查找。
后序遍历(左右中)就是天然的回溯过程,可以根据左右子树的返回值,来处理中节点的逻辑。
首先注意题目条件:二叉树节点数值是不重复的,而且一定存在 q 和 p (故不考虑异常)。
情况一:首先最容易想到的一个情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
判断逻辑是 如果递归遍历遇到q,就将q返回,遇到p 就将p返回,那么如果 左右子树的返回值都不为空,说明此时的中节点,一定是q 和p 的最近祖先。
情况二:节点本身p(q),它拥有一个子孙节点q(p)。
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;
if(left != NULL && right == NULL) return left;
if(right != NULL && left == NULL) return right;
return NULL;
}
};
在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。
题目:235.二叉搜索树的最近公共祖先
理解上面那道题,本题迎刃而解。
如果root->val比eft->val和right->val都大,则公共祖先一定不出现在左子树,left = NULL这个假设满足题意;如果root->val比eft->val和right->val都小,则公共祖先一定不出现在右子树,right = NULL这个假设满足题意。
有一点易错点,题目并没有说p和q谁的val更大,因此在if的判断中需要分别比较root->val和left->val和right->val的大小,不能主观认为q->val一定大于p->val。
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 = NULL;
TreeNode *right = NULL; //需先假设left和right为空
if(root->val > p->val && root->val > q->val){
left = lowestCommonAncestor(root->left, p, q);
}else if(root->val < p->val && root->val < q->val){
right = lowestCommonAncestor(root->right, p, q);
}else{
left = lowestCommonAncestor(root->left, p, q);
right = lowestCommonAncestor(root->right, p, q);
}
if(left != NULL && right != NULL) return root;
if(left != NULL && right == NULL) return left;
if(left == NULL && right != NULL) return right;
return NULL;
}
};