递归搜索回溯介绍





一、汉诺塔
面试题 08.06. 汉诺塔问题 - 力扣(LeetCode)


N=2,得先把最大的弄到C,那么剩下的上面的要先弄到b,相当于B是辅助柱,C是目标柱
N=3,要把最大的先弄到C,就得先把剩下的上面的弄到B,相当于N=2的情况,此时C是辅助柱子,B是目标柱子
N=4,要把最大的弄到C,就得先把剩下的上面弄到B,相当于N=3的情况,此时C是辅助柱子,B是目标柱子,然后再把B里面最大的弄到C,相当于A是辅助柱子,C是目标柱子,然后再把A最大的弄到C,相当于N=2的情况,B是辅助柱子,C是目标柱子,
我们发现不管N=多少,每一步都是为了把相对最大的弄到C,都是对最开始柱子最大的弄到目标柱子,剩下那个柱子当辅助柱子,对于最大的盘子,我们要通过将剩余的全部盘子通过目标柱子弄进辅助柱子,才能将最大盘子弄进目标柱子,操作都是一样,只是柱子不一样。于是可以联想到递归。
因为解决大问题,出现了相同的子问题,解决子问题又发现了出现相同的更小的子问题。

class Solution {
public:
void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {
dfs(A,B,C,A.size());
}
//(起始柱子,辅助柱子,目标柱子,转移盘子数)
void dfs(vector<int>& A, vector<int>& B, vector<int>& C,int n)
{
//递归退出条件
if(n==1)
{
C.push_back(A.back());
A.pop_back();
return;
}
//先把n-1个柱子通过目标柱子转移到辅助柱子,让相对最大的那个转移过去
dfs(A,C,B,n-1);
//相对最大的那个转移过去
C.push_back(A.back());
A.pop_back();
//宏观得看,再将n-1个柱子从辅助柱子上,通过起始柱子,转移到目标柱子
//相信dfs可以完成
dfs(B,A,C,n-1);
}
};
二、合并两个有序链表



递归的本质就是所有的问题都能转化为一个小问题,这里的小问题就是比大小,小的让它next拼接上后面剩余所有合并的结果就解决了,递归终止条件是看谁先没,就return剩下的那些。
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
return dfs(list1,list2);
}
ListNode* dfs(ListNode* list1, ListNode* list2)
{
//递归终止条件
if(list1==nullptr)return list2;
if(list2==nullptr)return list1;
//谁小,谁的next指向剩下的结果
if(list1->val<list2->val)
{
//1小,1的next指向1这个位置后面剩下的拼接结果
list1->next=dfs(list1->next,list2);
return list1;
}
list2->next=dfs(list1,list2->next);
return list2;
}
};
三、反转链表


很经典的题目,已经写过六七八次了
让处理好的next指针指向前边第一个未加入处理的结点,最后让 原始链表的头结点指向空就行
对于每层调用:让当前结点next的next指向当前结点,然后当前结点next指向空,每层调用存一个末尾结点当newhead返回


class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==nullptr||head->next==nullptr)return head;
//head->next找到末尾节点
ListNode* newhead=reverseList(head->next);
//每层结点子问题处理
head->next->next=head;
head->next=nullptr;
return newhead;
}
};
四、两两交换链表中的节点


问题可以转换成每两个结点为一组的递归子问题
单个或者头结点是空直接返回
对于每层递归:存tmp为归后的整体,存新的头为head的next,然后headnext的next指向本身,head的next指向tmp这个整体,返回newhead
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head==nullptr||head->next==nullptr)return head;
ListNode*tmp=swapPairs(head->next->next);
ListNode*newhead=head->next;
head->next->next=head;
head->next=tmp;
return newhead;
}
};
五、k个一组反转链表

class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode*tail=head;
//找到前k的节点后的一个节点
//该节点既可以用在这层当作结束标志
//也可以作为下一层的开始节点
for(int i=0;i<k;++i)
{
//先判断!
if(tail==nullptr)return head;
tail=tail->next;
}
ListNode*prev=nullptr,*cur=head;
while(cur!=tail)
{
//存一下下个节点
ListNode*tmp=cur->next;
//逆转
cur->next=prev;
//更新
prev=cur;
cur=tmp;
}
head->next=reverseKGroup(tail,k);
return prev;
}
};
六、Pow(x,n)

class Solution {
public:
double myPow(double x, int n) {
//负数转正数可能会溢出,要注意!!!
return n<0?1.0/pow(x,-(long long)n):pow(x,n);
}
double pow(double x,int n)
{
if(n==0)return 1.0;
double tmp=pow(x,n/2);
return n%2==0?tmp*tmp:tmp*tmp*x;
}
};
完。

被折叠的 条评论
为什么被折叠?



