剑指offer——Day19 搜索与回溯算法(中等)

Day19 2023.2.1 搜索与回溯算法(中等)

剑指offer 64. 求1+2+...+n

自己实现

……不让用if、else等条件判断语句?那递归出口怎么写,难住了,直接看题解

题解

使用条件判断语句的短路效应……太搞了

比如要达到if(n>1)的效果,可以使用bool x = n>1 && ...(if内的语句)

参考题解代码如下:

class Solution {
public:
    int sumNums(int n) {
        bool x = n>1 && (n+=sumNums(n-1));
        return n;
    }
};

代码表现

hint:

  • 完全可以利用条件判断的短路效应来起到if-else语句的作用,不太常见,长见识了

剑指offer 68 - Ⅰ. 二叉搜索树的最近公共祖先

自己实现

没有思路。这个虽然给了二叉搜索树的特殊数据结构,但是怎么做到从p、q两个节点往上走能够同步判断到正确的公共节点。直接看题解了

题解

这个题的关键点在于最近公共祖先的判定方式。这里假设给出的两个节点为p, q,最近公共祖先为res,遍历变量为root

那么以res作为分割

  • 对于res往上的节点rootp, q只会在root的同一侧子树中
  • 对于res往下的节点rootp, q不会再有公共节点了

另外,通过二叉搜索树,如果p, qroot的大小比较结果相同,则证明p, q是同一侧子树中;反之相反

因此,只需要比较p, qroot大小比较结果是否相同,就能直到root是不是最近公共祖先

这个题目的突破点就在于此,这一点破除之后,就很简单了

参考题解代码如下:

迭代法

/**
 * 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==NULL)return NULL;
        if(p->val<q->val){
            TreeNode* tmp=p;
            p=q;
            q=tmp;
        }
        while(root!=NULL){
            if(p->val<root->val)root=root->left;
            else if(q->val>root->val)root=root->right;
            else break;
        }
        return root;
    }
};

递归法

/**
 * 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 {
    TreeNode* res;
    int val_p, val_q;
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL)return NULL;
        if(p->val<q->val){
            TreeNode* tmp=p;
            p=q;
            q=tmp;
        }
        val_p=p->val;
        val_q=q->val;
        recur(root);
        return res;
    }
    void recur(TreeNode* root){
        if(root==NULL)return;
        if(val_p<root->val)recur(root->left);
        else if(val_q>root->val)recur(root->right);
        else res=root;
    }
};

代码表现

迭代法

递归法

hint:

  • 对于这种给了特殊条件如二叉搜索树的问题,可以多考虑考虑这会带来什么便利,将题目要求转化之后再编写条件判断,或许会简单很多
  • 同时,这个地方事先将p, q的大小关系确定大小优化了后面的条件判断

剑指offer 68 - Ⅱ. 二叉树的最近公共祖先

自己实现

自己实现的时候还是卡在了和上一题一样的顾虑上,即不能做到同步回溯到达正确的root。直接看了题解,但其实还是要从rootp, q本质关系出发

题解

  1. 终止条件
    1. 当越过叶节点,则直接返回 null ;
    2. 当 root 等于 p,q ,则直接返回 root ;
  2. 递推工作
    1. 开启递归左子节点,返回值记为 left ;
    2. 开启递归右子节点,返回值记为 right ;
  3. 返回值
    1. 当 left 和 right 同时为空 :说明 root 的左 / 右子树中都不包含 p,q ,返回 null ;
    2. 当 left 和 right 同时不为空 :说明 p,q 分列在 root 的 异侧 (分别在 左 / 右子树),因此 root 为最近公共祖先,返回 root ;
    3. 当 left 为空 ,right 不为空 :p,q 都不在 root 的左子树中,直接返回 right 。具体可分为两种情况:
      1. p,q 其中一个在 root 的 右子树 中,此时 right 指向 p(假设为 p );
      2. p,q 两节点都在 root 的 右子树 中,此时的 right 指向 最近公共祖先节点
    4. 当 left 不为空 , right 为空 :与情况 3. 同理;

代码如下:

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == nullptr || root == p || root == q) return root;
        TreeNode *left = lowestCommonAncestor(root->left, p, q);
        TreeNode *right = lowestCommonAncestor(root->right, p, q);
        if(left == nullptr) return right;
        if(right == nullptr) return left;
        return root;
    }
};

代码效果

hint:

  • 还是那句话,从源头出发,没有思路的时候试试分析本质的关系,将可能情况进行列举分类,思路就清晰很多了
posted @ 2023-02-01 16:20  神鹏佐佑  阅读(14)  评论(0)    收藏  举报