合并两个有序数组
方法一:递归方法
两个链表头部值较小的一个节点与剩下元素的merge操作结果合并
- 时间复杂度:O(m+n),因为每次递归调用函数都会去掉list1或者list2的头节点,之道至少有一个链表为空,函数至多只会调用每个节点一次,所以时间复杂度取决于合并后的链表长度,所以时间复杂度为O(m+n)
- 空间复杂度:O(m+n) ,其中m和n为链表长度,递归调用函数时需要消耗栈空间,栈空间的大小取决于递归调用的深度,结束递归调用mergeTwoLists函数最多调用m+n次,所以空间复杂度为O(m+n)
递归过程如下图所示:
//递归的思路就是在剩下元素里寻找最小的元素,接在当前结点的next指针下
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if(list1==null) return list2;
else if(list2==null) return list1;
//当list1或者list2为空时,不需处理,直接返回另一个链表。
if(list1.val<=list2.val){
list1.next=mergeTwoLists(list1.next, list2);
return list1;//这里返回的时剩余结点的最小结点。此list是指代剩余结点的头节点,而非初始链表的头节点。
}else{
list2.next=mergeTwoLists(list1, list2.next);
return list2;
}
}
}
方法二:迭代
- 时间复杂度:O(m+n),m和n为链表的长度,每次迭代都会有一个元素会被放进合并链表中,因此while的循环次数哦最多不会超过两个链表的长度值和。所有其他操作的时间复杂度都是常数级别的,所以时间复杂度为O(m+n)
- 空间复杂度:O(1),我们只需要常数的空间来存放变量。
建立一个新的链表newhead,相当于从list1和list2中向newhead尾插新元素。定义一个r用于标记newhead的尾节点用于尾插。
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if(list1==null) return list2;
else if(list2==null) return list1;
//当list1或者list2为空时,不需处理,直接返回另一个链表。
ListNode newhead=new ListNode();//定义一个新的头节点
ListNode r=newhead; //r用来让新的链表加入元素
while(list1!=null&&list2!=null){
if(list1.val<=list2.val){
r.next=list1;
list1=list1.next;
}else{
r.next=list2;
list2=list2.next;
}
r=r.next; //保持让r指向新的链表链尾元素
}
if(r.next==list1){//判断r后面跟的是list1还是list2
r.next=list2;//如果r.next指向的是list1,说明list1先为null的,则需要将r与list2剩余元素建立连接
}else{
r.next=list1;
}
return newhead.next;
}
}