剑指Offer(十六)——合并两个排序的链表(非递归有图)
题目描述:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
设计思想:把一个链表pHead2的所有元素逐个插入到另一链表pHead1中。
最外层是一个while循环遍历pHead2的所有节点。
推荐直接阅读一开始的四张图片,了解一般情况下的插入
1.先考虑一般情况:
设定node1为pHead1当前节点,node2为pHead2当前节点。
情况一:若node1的val 小于等于 node2的val
此时又有两种情况
a.node2在node1和temp1之间
对于该情况我们相当于node1后尾部插入节点node2先转移节点完后要调整新的指向。所以转移节点指向前要保存node1->next和node2->next。
具体代码:

1 //保存下一节点 2 temp1 = node1->next; 3 temp2 = node2->next; 4 //转移节点指向 5 node1->next = node2; 6 node2->next = temp1; 7 //更新变量 8 node1 = temp1; 9 pre1 = node2; 10 node2 = temp2;
b.node2大于node1也大于node1的下一节点
此时我们就要对上面的代码进行if判断时候temp1小于node2进入到本情况
//新加判断,我们要找到node1 的下一节点比node2大的位置。找到后就回到了尾部插入的情况。 (若找到phead1的结尾也没找到,下面再讨论。)

1 //保存下一节点 2 temp1 = node1->next; 3 temp2 = node2->next; 4 5 //新加判断,我们要找到node1 的下一节点比node2大的位置 6 while (temp1 != NULL && temp1->val <= node2->val) 7 { 8 node1 = temp1; 9 temp1 = temp1->next; 10 } 11 12 //转移节点指向 13 node1->next = node2; 14 node2->next = temp1; 15 //更新变量 16 node1 = temp1; 17 pre1 = node2; 18 node2 = temp2; 19
若node1的val 大于 node2的val
头部插入,需要用到node1的前一节点pre。

1 if (node1->val <= node2->val) 2 { 3 temp1 = node1->next; 4 temp2 = node2->next; 5 6 //新增一个找到满足node2位于temp1和node1之间的状态 7 while (temp1 != NULL && temp1->val <= node2->val) 8 { 9 node1 = temp1; 10 temp1 = temp1->next; 11 } 12 13 node1->next = node2; 14 node2->next = temp1; 15 16 node1 = temp1; 17 pre1 = node2; 18 node2 = temp2;
2.针对特殊情况的考虑:
情况一可能出现问题:pHead1到头了,node1->next是空。
保存完,在节点指向转移前,就是还没有下面的红线的时候,我们要判断temp1==NULL吗?
若为空
此时我们pHead2的node2后的节点(包括node2)都大于pHead1的node1后的节点,
因为pHead1遍历完最后一个元素值node1小于phead2的某一节点,那phead2之后的所有节点都大于phead1的最后一个节点了。
所以我们直接把所有node2后所有的节点都插入到node1后就ok了。直接node1-》next=node2;

1 temp1 = node1->next; 2 temp2 = node2->next; 3 4 while (temp1 != NULL && temp1->val <= node2->val) 5 { 6 node1 = temp1; 7 temp1 = temp1->next; 8 } 9 10 11 if (temp1 == NULL) 12 { 13 //链表pHead1完了,把所有的pHead2剩下节点尾部插入node1后面; 14 node1->next = node2; 15 break; 16 } 17 node1->next = node2; 18 node2->next = temp1; 19 20 node1 = temp1; 21 pre1 = node2; 22 node2 = temp2;
情况2可能出现问题:循环一开始node1=pHead1,pre=null;
此时我们要再节点指向修改前加判断
if(pre==NULL)
{node2->next=node1;pre=node2;pHead1=pre;}
具体代码:

1 //保存信息 2 temp2=node2->next; 3 //修改节点指向 4 if(pre1==NULL) 5 { 6 node2->next=node1; 7 pre1=node2; 8 pHead1=pre1; 9 10 } 11 else 12 { 13 //修改指向 14 node2->next=node1; 15 pre1->next=node2; 16 //更新变量 17 pre1=node2; 18 node2=temp2; 19 }
3. 将上面代码写到while循环里即我们的最终代码

1 /* 2 struct ListNode { 3 int val; 4 struct ListNode *next; 5 ListNode(int x) : 6 val(x), next(NULL) { 7 } 8 };*/ 9 class Solution { 10 public: 11 static ListNode* Merge(ListNode* pHead1, ListNode* pHead2) 12 { 13 //对特殊输入处理 14 if (pHead1 == NULL) { return pHead2; } 15 if (pHead2 == NULL) { return pHead1; } 16 17 18 //我们把pHead2插入到pHead1中 19 ListNode* node1 = pHead1, *node2 = pHead2; 20 ListNode* pre1 = NULL;//node1的前一节点,初始为空 21 ListNode* temp1, *temp2; 22 while (node2 != NULL) 23 { 24 if (node1->val <= node2->val) 25 { 26 //保存下一节点 27 temp1 = node1->next; 28 temp2 = node2->next; 29 while (temp1 != NULL && temp1->val <= node2->val) 30 { 31 node1 = temp1; 32 temp1 = temp1->next; 33 } 34 if (temp1 == NULL) 35 { 36 //链表pHead1完了,把所有的pHead2剩下节点尾部插入node1后面; 37 node1->next = node2; 38 break; 39 } 40 //转移节点指向 41 node1->next = node2; 42 node2->next = temp1; 43 //更新变量 44 node1 = temp1; 45 pre1 = node2; 46 node2 = temp2; 47 48 } 49 else 50 { 51 temp2 = node2->next; 52 node2->next = node1; 53 if (pre1 == NULL) 54 { 55 pre1 = node2; 56 } 57 else 58 { 59 pre1->next = node2; 60 pre1 = pre1->next; 61 node2 = temp2; 62 } 63 } 64 } 65 return pHead1; 66 67 } 68 }; 69 70
牛客网运行截图:
PS:补充查到的一个递归解法感觉比较清晰
附上递归代码:这个不是C++应该是java或C#的代码
public class Solution { public ListNode Merge(ListNode list1,ListNode list2) { if(list1 == null && list2 == null) return null; if(list1 == null) return list2; if(list2 == null) return list1; if(list1.val <= list2.val){ list1.next = Merge(list1.next, list2); return list1; }else{ list2.next = Merge(list1, list2.next); return list2; } } }
---恢复内容结束---