前言
昨天学习了递归和分治算法,我的学习感受就是:递归的概念挺好理解,但是在解决题目的过程中常常会因为纠结多层函数嵌套,很容易把自己绕进去,在完全理解后才发现其实不用纠结细枝末节,理解函数的作用并且调用就可以了,剩下的思路是让计算机完成的,而不是我的大脑。今天在力扣上找了到链表和递归结合的题目。之所以选择这道题目,是因为在数据结构与算法这门课中,链表是开篇基础,也是重要的数据结构之一,在复习链表的同时也希望加深自己对递归的理解。
一、题目描述:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
提示:
- 两个链表的节点数目范围是
[0, 50] -100 <= Node.val <= 100l1和l2均按 非递减顺序 排列
来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/me…
二、思路分析:
递归和迭代不分家,可看到这个题目,我第一想用的是迭代,思路是设置一个虚拟节点newHead,命令一个指针pi作为前进指针,即
ListNode newHead(0); ListNode *pi = &newHead;,当链表l1和链表l2都不为空链表时,执行while循环,当l1中节点的最小值小于l2节点中的最小值,将指针pi的下一个节点指向链表l1,同时,l1向前遍历一个,反之则指向链表l2,同时指针pi也向前进一位。
pi->next = l1;
l1 = l1->next;
直到链表l1和l2其中一个为空的时候,将剩下的链表接在pi的后面
pi = pi->next;
最后返回newHead.next
第二,就是常用的递归方法,递归的本质是不断地调用函数,所以一定需要设置一个终止条件时的递归停止,不然,这个代码的时间复杂度就太大了,在这个题目中,递归的终止条件应该是当l1和l2链表其中任一为空,停止调用。整体思路大概为: 当链表l1中节点的最小值小于链表l2节点的最小值时,将链表l1->next和l2为头节点的两个链表一起合并,然后再返回那个最小的链表,即
if(l1->val < l2->val){
l1->next = mergeTwoLists(l1->next,l2);
return l1;
}
而当其中任一链表为空,说明链表合并已经全部完成,直接返回剩下的链表就可以了。
if(l1==NULL)
return l2;
if(l2==NULL)
return l1;
三、AC 代码:
迭代法
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode newHead(0);
ListNode *pi = &newHead;
while(l1 && l2) {
if(l1->val < l2->val) {
pi->next = l1;
l1 = l1->next;
}else{
pi->next = l2;
l1 = l1->next;
}
pi = pi->next;
}
pi->next = (l1 != null) ? l1 : l2; // 遍历后剩余的非空列表接在pi后面
return newHead.next;
}
};
递归法
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1==NULL)
return l2;
if(l2==NULL)
return l1;
if(l1->val < l2->val){
l1->next = mergeTwoLists(l1->next,l2);
return l1;
}else{
l2->next = mergeTwoLists(l1,l2->next);
return l2;
}
}
};
四、总结:
虽然这道题的难度标为简单,但是为了理解这道题目,还是查找了很多知识,也耗费了不少时间,也发现了其实我对链表也不是很熟悉。。。最后,谢谢阅读到这里的你,如果你觉得我的文章有助于理解的话,请帮我点个赞吧
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情