题目内容
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
题目分析
这道题算是很基本的一道题,基本O(n)
的复杂度就能完成,这道题的解题思想就是:在遍历两个链表的过程中,比较此时访问的结点,value较小的结点就加入到最后要返回的链表中。有所不同可能是从前合并结点还是从后合并结点,即递归和非递归的写法。
解题
非递归解法
这种方法思路很简单,新创建一个链表,比较pHead1和pHead2,哪个结点的value小就插入新链表,如果某一个链表先被遍历完,那么另一个链表的剩下部分,直接插入新链表。
下面用表格演示一个过程,ListNode1: {1, 3, 5, 6)
和ListNode2: {2, 4}
,用加粗表示当前访问结点
状态 | ListNode1 | ListNode2 | newList |
---|---|---|---|
初始状态 | {1, 3, 5, 6} | {2, 4} | {} |
1 < 2 | {3, 5, 6} | {2, 4} | {1} |
3 > 2 | {3, 5, 6} | {4} | {1, 2} |
3 < 4 | {5, 6} | {4} | {1, 2, 3} |
5 > 4 | {5, 6} | {} | {1, 2, 3, 4} |
ListNode2为NULL | {} | {} | {1, 2, 3, 4, 5, 6} |
代码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
ListNode* newHead = new ListNode(1);
ListNode* nowNode = newHead;
if(pHead1 == NULL)
return pHead2;
if(pHead2 == NULL)
return pHead1;
while(pHead1 != NULL && pHead2 != NULL){
if(pHead1->val <= pHead2->val){
nowNode->next = pHead1;
pHead1 = pHead1->next;
}else{
nowNode->next = pHead2;
pHead2 = pHead2->next;
}
nowNode = nowNode->next;
}
if(pHead1 != NULL){
nowNode->next = pHead1;
}
if(pHead2 != NULL){
nowNode->next = pHead2;
}
return newHead->next;
}
};
递归解法
这种思路其实和上一种方法差不多,只不过并没有显式地创建一个新的链表,而是因为递归的缘故从末尾开始比较,最后全部归到pHead1或者pHead2。
下面用表格演示一个过程,pHead1: {1, 3, 5, 6)
和pHead2: {2, 4}
,用加粗表示当前访问结点
状态 | pHead1 | pHead2 | 说明 |
---|---|---|---|
初始状态 | {1, 3, 5, 6} | {2, 4} | 1 < 2,在pHead1进入递归,访问下一个结点 |
第1次递归 | {1, 3, 5, 6} | {2, 4} | 3 > 2,在pHead2进入递归,访问下一个结点 |
第2次递归 | {1, 3, 5, 6} | {2, 4} | 3 < 4,在pHead1进入递归,访问下一个结点 |
第3次递归 | {1, 3, 5, 6} | {2, 4} | 5 > 4,在pHead2进入递归,访问下一个结点 |
第4次递归 | {1, 3, 5, 6} | {2, 4} | 因为pHead2下一个结点为NULL,因此返回当前pHead1,结果给第3次递归的pHead2->next ,返回上一层递归 |
第3次递归 | {1, 3, 5, 6} | {2, 4 , 5, 6} | 因为从第2次递归进入第3次递归,是从pHead1进入的,所以返回当前pHead2,结果给第2次递归的pHead1->next ,返回上一层递归 |
第2次递归 | {1, 3, 4, 5, 6} | {2, 4 , 5, 6} | 因为从第1次递归进入第2次递归,是从pHead2进入的,所以返回当前pHead1,结果给第1次递归的pHead2->next ,返回上一层递归 |
第1次递归 | {1, 3, 4, 5, 6} | {2, 3, 4, 5, 6} | 因为进入第1次递归,是从pHead1进入的,所以返回当前pHead2,结果给初始的pHead1->next ,返回上一层递归 |
结果pHead1 | {1, 2, 3, 4, 5, 6} | {2, 3, 4, 5, 6} | 返回结果pHead1 |
表述的不太好,请结合代码观看。
代码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL)
return pHead2;
if(pHead2 == NULL)
return pHead1;
if(pHead1->val < pHead2->val){
pHead1->next = Merge(pHead1->next, pHead2);
return pHead1;
}else{
pHead2->next = Merge(pHead1, pHead2->next);
return pHead2;
}
}
};
进阶版非递归解法
这种方法的思路和第一种方法类似,但是我们不再是以创建一个新链表,而是在比较的过程中,把另一条链表合并到我指定的链表中。如果指定链表的下一个结点比另一条链表的结点小,那么指定链表继续向下访问链表;反之,另一个链表的当前结点插入到指定链表的当前结点和下一个结点之间。
虽然听起来难度不大,但是加粗部分的代码实现逻辑较为繁杂,下面用图表示,请参照代码理解过程。
代码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL)
return pHead2;
if(pHead2 == NULL)
return pHead1;
ListNode* newHead;
if(pHead1->val > pHead2->val){
newHead = pHead1;
pHead1 = pHead2;
pHead2 = newHead;
}
newHead = pHead1;
while(pHead1->next != NULL && pHead2 != NULL){
if(pHead1->next->val > pHead2->val){
ListNode* temp = pHead1->next;
pHead1->next = pHead2;
pHead2 = pHead2->next;
pHead1 = pHead1->next;
pHead1->next = temp;
}else{
pHead1 = pHead1->next;
}
}
if(pHead2 != NULL){
pHead1->next = pHead2;
}
return newHead;
}
};
进阶版递归算法
思路与上一种方法一致,但是是递归实现,所以合并过程是从后往前进行的。
代码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL)
return pHead2;
if(pHead2 == NULL)
return pHead1;
if(pHead1 != NULL && pHead2 != NULL){
if(pHead1->val > pHead2->val){
ListNode* temp = pHead1;
pHead1 = pHead2;
pHead2 = temp;
}
pHead1->next = Merge(pHead1->next, pHead2);
}
return pHead1;
}
};
以上思路为个人想法和网络各位大佬的题解的结合,欢迎讨论与指正。