第二十三天 | 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236.二叉树的最近公共祖先 235.二叉搜索树的最近公共祖先

题目: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; 
    }
};

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值