剑指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往上的节点root,p,q只会在root的同一侧子树中 - 对于
res往下的节点root,p,q不会再有公共节点了
另外,通过二叉搜索树,如果p, q与root的大小比较结果相同,则证明p, q是同一侧子树中;反之相反
因此,只需要比较p, q与root大小比较结果是否相同,就能直到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。直接看了题解,但其实还是要从root和p, q的本质关系出发
题解
- 终止条件
- 当越过叶节点,则直接返回 null ;
- 当 root 等于 p,q ,则直接返回 root ;
- 递推工作
- 开启递归左子节点,返回值记为 left ;
- 开启递归右子节点,返回值记为 right ;
- 返回值
- 当 left 和 right 同时为空 :说明 root 的左 / 右子树中都不包含 p,q ,返回 null ;
- 当 left 和 right 同时不为空 :说明 p,q 分列在 root 的 异侧 (分别在 左 / 右子树),因此 root 为最近公共祖先,返回 root ;
- 当 left 为空 ,right 不为空 :p,q 都不在 root 的左子树中,直接返回 right 。具体可分为两种情况:
- p,q 其中一个在 root 的 右子树 中,此时 right 指向 p(假设为 p );
- p,q 两节点都在 root 的 右子树 中,此时的 right 指向 最近公共祖先节点 ;
- 当 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:
- 还是那句话,从源头出发,没有思路的时候试试分析本质的关系,将可能情况进行列举分类,思路就清晰很多了
浙公网安备 33010602011771号