leetcode链接:https://leetcode.cn/problems/merge-two-sorted-lists/description/
浅浅带过一下使用非递归的方式:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
//1.创建头节点
ListNode *newHead = new ListNode(0);
//2.创建用于迭代的结点
ListNode *prev = newHead;
while(list1 != nullptr && list2 != nullptr)
{
if (list1->val < list2->val)
{
prev->next = list1;
list1 = list1->next;
}
else
{
prev->next = list2;
list2 = list2->next;
}
//prev结点迭代
prev = prev->next;
}
//处理没有被链入的结点
prev->next = list1 == nullptr ? list2 : list1;
//释放头节点
prev = newHead->next;
delete newHead;
return prev;
}
};
使用递归
使用递归必须要思考下面三个问题:
1.找到重复的子问题
2.具体某一个子问题在做什么事情
3.找到递归的出口
1.找到重复的子问题
子问题:将L1和L2中较小的一个作为头节点,合并剩下的链表
函数头:
dfs(list1, list2);
2.具体某一个子问题在做什么事情
第一步:比较节点的大小
第二步:将小的节点的next链接到下一个小的节点的前面
l1->next = dfs(l1->next, l2);
或者
l2->next = dfs(l2->next, l1);
3.防止死递归
当l1
为空或者l2
为空的时候,退出
代码:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
return dfs(list1, list2);
}
ListNode* dfs(ListNode* list1, ListNode* list2)
{
//1.找到递归的出口
if (list1 == nullptr)
return list2;
if (list2 == nullptr)
return list1;
//2.1 找到小的那个节点
if (list1->val < list2->val)
{
//2.2合并链表
list1->next = dfs(list1->next, list2);
//2.3返回头节点
return list1;
}
else
{
list2->next = dfs(list2->next, list1);
return list2;
}
}
};
总结:
循环 vs 递归
循环:处理重复的子问题
递归:有重复的子问题,进行处理
因此,循环和递归可以互相转化
什么时候用循环?什么时候用递归?
使用递归的问题,如果想改成循环,需要借助栈。而如果借助栈,使用循环,就会很麻烦!
什么样的情况适用递归?递归调用类似下面这种情况
什么样的情况适用循环?递归调用类似下面这种情况
只有一个分支,递归改成循环就很简单。
举例:遍历数组
递归 vs 深搜
递归的展开头图,其实就是对一棵树做一次深度优先遍历(dfs)