题目来自于leetcode,要求是将两个已经有序的链表拼接成一个有序的链表,链表结构如下:
public class ListNode{ int val; ListNode next; ListNode(int x){ val=x; } }
示意图如下,一个长方形成为节点,一个链表至少有一个节点。
方法一:首先创建一个新的链表L,比较了L1和L2当前结点的Val,小的加入到L中,同时将节点向后移,
直到有一个链表为空。最后将另一个非空的链表添加到L即可。时间复杂度为O(n+m).
Header:新链表的头节点,pre作为当前链表的最后一个节点,具体步骤如下:
1.判断L1和L2其中一个是否为空,若有为空,执行3,否则执行2
2.比较L1和L2的Val值,小的添加到pre节点的后面,并向右移动一个节点(ListNode=ListNode.next,注意此时链表ListNode已经发生改变了),
同时pre指向Header链表的最后一个。执行1.
3.若L1不为空,则将L1添加到pre的后面。若L2不为空则将L2添加到pre节点的后面。
具体实现代码如下:
public ListNode mergeTwoLists(ListNode l1, ListNode l2){ ListNode header=new ListNode(0); ListNode pre=header; while(l1!=null&&l2!=null){ if(l1.val>l2.val){ pre.next=l2; l2=l2.next; }else{ pre.next=l1; l1=l1.next; } pre=pre.next; } if(l2!=null){ pre.next=l2; } if(l1!=null){ pre.next=l1; } return header.next; }
方法二:由于L1和L2已经是有序了,所以可以考虑将L2插入到L1中,这里只讲插入操作怎么进行,具体过程看java代码
Header 任然为头结点,pre为当前节点的末节点,,红线代表需要修改的指向,绿线代表需要删除的指向
,现在考虑L2的Val比L1小的情况,
插入步骤如下:
1。保留L2下一个节点为next
2.修改L2下一个节点的指向为pre指向的下个节点
3.修改pre指向的节点为L2
4.将pre和L2各自向右移动一个节点
具体代码如下:
public ListNode mergeTwoLists(ListNode l1, ListNode l2){ ListNode helper=new ListNode(0); ListNode pre=helper; helper.next=l1; while(l1!=null&&l2!=null){ if(l1.val>l2.val){ ListNode next=l2.next; l2.next=pre.next; pre.next=l2; l2=next; }else{ l1=l1.next; } pre=pre.next; } if(l2!=null){ pre.next=l2; } return helper.next; }
方法3:采用递归的思想,若将函数看成求两个链表当前较小的节点,递归结束为两个链表中有一个为null。
步骤一:1.创建一个节点header为L1和L2较小的节点
2.创建一个中间变量nonheader为L1和L2较大的节点
· 3.将header下个节点指向递归函数的返回结果,但此时传参中header已经向右移动了一个单位
代码如下:
public ListNode mergeTwoLists(ListNode l1, ListNode l2) { if(l1==null) return l1; if(l2==null) return l2; ListNode head=(l1.val<l2.val)?l1:l2; ListNode nonhead=(l1.val<l2.val)?l2:l1; head.next=mergeTwoLists(head.next,nonhead); return head; }
这三种方法都可以实现,总体效果最好的时递归的方法。如有纰漏,希望能得到大家的帮助。