关于力扣上面的两道链表的简单题运用递归的形式实现;
(1)给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例:1->2->3->4->5 反转后的输出结果为 5->4->3->2->1
分析: 看到这种题,大多数人想到的就是利用指针法,改变指针指向的顺序以此来达到逆转的方法,但其实这种题型也可以利用递归的方法实现,处理链表的很多问题都可以利用递归来解决,我们先来回顾一下何时才能使用递归。1、大问题能够拆解成多个子问题 2、子问题和大问题求解方式一样 3、存在最小子问题。很多人恐惧递归,无非是题目做少了或者是不想画图一步步分析,现在我带大家依次分析一下。
首先所给示例为:
我们发现需要先将head和其后面的元素进行反转,我们再次作图观察发现现仍需反转head和head后一个元素的位置,与上一步情况相同:
我们再次分解此大问题得到一下情形:
同样的,如上两图都与大问题情况相似,需逆转head结点和其后节点的位置,我们继续分析:
我们发现当head结点只剩下最后一个时,是无法与后一个结点进行逆转的,此时我们发现存在最小子问题,通过以上分析,我们发现此题满足使用递归的三种条件,我们即可使用递归来求解此题。
递归的这个过程分为递和归两个步骤来完成,我们先来分析递的过程,顾名思义,递这个过程就是将大问题拆解成小问题的过程,如上图所示,那么什么时候结束递的过程呢,就是达到了最小子问题,无法进行下一步递的过程,即head指针指向了5,此时反转5这个结点没有意义,即可跳出递的这个条件。接着分析下归的过程,归的过程就是将每个子问题按题意处理好,根据题意我们可以知道我们需将每个子问题都逆转,那么我们来分析逆转的这个操作该如何进行,下图选取一个子问题。
要将4,5这两个位置逆转,即是逆转他们的指针,将5的下一个位置指向4;那么我们就可以将指向4的head指针的next位置(即指向5的指针)的next指针指向4,然后再将指向4的head指针的next指针指向空,这样子问题的逆转就被解决了
分析完毕,现在我们可以写出代码
class Solution {
public:
ListNode* reverseList(ListNode* head)
{
//递归终止条件,如果当前没有元素或者只有一个元素时返回
if(head==nullptr||head->next==nullptr)
{
return head;
}
//不断进行递归调用,返回反转的链表。p指向的是每次归的过程返回的最后一个结点
ListNode *p=reverseList(head->next);
//具体的反转步骤,归的过程需要做的事情
head->next->next=head;
head->next=nullptr;
//最后返回p即可
return p;
}
};
以上反转链表的递归实现方法,下面写迭代的方法:
class Solution {
public:
ListNode* reverseList(ListNode* head)
{
ListNode *cur=nullptr;
ListNode *prev=head;
while(prev!=nullptr)
{
ListNode *p=prev->next;
prev->next=cur;
cur=prev;
prev=p;
}
return cur;
}
};
(2)将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:1->2->4和1->3->4 合并后返回的结果是1->1->2->3->4->4
我们发现此题也满足递归的三种条件,1、大问题能够拆解成多个子问题 2、子问题和大问题求解方式一样 3、存在最小子问题。两个链表的合并可以分解成两个链表中每个元素之间的比较和合并,且求解方法同样相同,两条链表中的一条遍历完了即为终止条件,另一条链表的剩余部分即可直接插入到合并的链表后面。下面写出递归的代码:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
//终止条件
if (l1 == nullptr) {
return l2;
} else if (l2 == nullptr) {
return l1;
}
//递归中比较两个链表中的元素值并且合并的步骤
//如果L1中元素的值小于L2中元素的值,则保留下L1中元素的值,L1的下一个元素为L1- >next和L2元素值比较的最小值,L2同理。
else if (l1->val < l2->val) {
l1->next = mergeTwoLists(l1->next, l2);
return l1;
} else {
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
}
};
下面写出迭代解决此题的代码:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* preHead = new ListNode(-1);
ListNode* prev = preHead;
while (l1 != nullptr && l2 != nullptr) {
if (l1->val < l2->val) {
prev->next = l1;
l1 = l1->next;
} else {
prev->next = l2;
l2 = l2->next;
}
prev = prev->next;
}
// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
prev->next = l1 == nullptr ? l2 : l1;
return preHead->next;
}
};