先看题,其实题目很明白:
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
这道题有递归和非递归做法,主要学习的是递归的想法。
题目的函数:
struct ListNode *mergeTwoLists(struct ListNode *l1, struct ListNode *l2){}
法一:递归
我们以下面这个例子来看怎么做递归:
1->6->7 头指针l1
2->5->8 头指针l2
l1的值比l2小,所以l1应该排在l2后面,但是不能直接就把l1->next指向l2,因为l2和l1->next的节点的值还没比过,所以得出结论,l1的next应该指向l2或者还是l1->next。
所以我们再次调用本函数,并且写成 l1->next=mergeTwoLists(l1->next,l2);
所以现在我们就可以写出一个条件判断语句了:
if (l1->val < l2->val)
l1->next = mergeTwoLists(l1->next, l2);
else
l2->next = mergeTwoLists(l1, l2->next);
一直递归调用函数,直到l1或者l2有一个是NULL,这时候我们可以写递归出口了。如果l1是空,那么上一个l1的值其实就比l2小了,l2应该排在最后面,这时不管l2到没到链表最后也没事,l2后面的节点的值都比l1的大,那么就直接返回l2。
if (l1 == NULL || l2 == NULL)
return l1 == NULL ? l2 : l1;
把递归出口放在函数开头。
但是我们这个函数返回的是指针类型,最后总归要return一个指针,return谁?
看看我们什么时候调用的:l1->next = mergeTwoLists(l1->next, l2);
如果是这个情况,mergeTwoLists(l1->next, l2)应该返回谁?我们之前分析的是l1的next应该指向l2或者还是l1->next。其实就是指向对应val小的那一个,所以我们要比较l1->next和l2的val的值谁小,而在递归函数中,l1->next被传值赋成了l1,所以就是比较下一个递归函数中l1,l2谁的val小,谁小就return谁。
return l1->val < l2->val ? l1 : l2;
合并我们上面给出的代码:
struct ListNode *mergeTwoLists(struct ListNode *l1, struct ListNode *l2) {
if (l1 == NULL || l2 == NULL)
return l1 == NULL ? l2 : l1;
if (l1->val < l2->val)
l1->next = mergeTwoLists(l1->next, l2);
else
l2->next = mergeTwoLists(l1, l2->next);
return l1->val < l2->val ? l1 : l2;
}
步骤图:(从左往右看)
法二:双指针
简单提一下双指针,就是l1和l2不停比较然后迭代,这个不详细说了,详情去看网上的题解吧。