输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
数据范围: 0≤n≤10000≤n≤1000,−1000≤节点值≤1000−1000≤节点值≤1000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
public ListNode Merge (ListNode pHead1, ListNode pHead2) {
// write code here
ListNode dummy=new ListNode(0);
ListNode current=dummy;//用于遍历新链表
//当两个链表都不为空时,循环比较
while(pHead1!=null&&pHead2!=null){
if(pHead1.val<=pHead2.val){
current.next=pHead1;
pHead1=pHead1.next;
}
else{
current.next=pHead2;
pHead2=pHead2.next;
}
current=current.next;
}
// 如果还有剩余节点,直接接到新链表的末尾
if (pHead1 != null) {
current.next = pHead1;
}
if (pHead2 != null) {
current.next = pHead2;
}
return dummy.next;
}
方法签名
public ListNode Merge(ListNode pHead1, ListNode pHead2) |
- 参数:接收两个链表的头节点
pHead1
和pHead2
作为输入。 - 返回值:返回合并后链表的头节点。
方法体
-
创建哨兵节点:
ListNode dummy = new ListNode(0);
这里创建了一个哨兵节点(dummy node),其值设置为0(实际上这个值并不重要,因为它只是用作一个占位符,帮助处理链表头部可能为空的情况)。
-
初始化当前节点:
ListNode current = dummy;
current
用于遍历新链表,初始时指向哨兵节点。 -
合并链表:
while (pHead1 != null && pHead2 != null) {
if (pHead1.val <= pHead2.val) {
current.next = pHead1;
pHead1 = pHead1.next;
} else {
current.next = pHead2;
pHead2 = pHead2.next;
}
current = current.next;
}
这个循环会持续遍历两个链表,直到其中一个链表被完全遍历完。在每次迭代中,它都会比较
pHead1
和pHead2
的当前节点的值,并将较小的节点接到新链表的末尾(实际上是接到current
节点的后面)。然后,它会移动相应的链表指针(pHead1
或pHead2
)和新链表指针current
。 -
处理剩余节点:
if (pHead1 != null) {
current.next = pHead1;
}
if (pHead2 != null) {
current.next = pHead2;
}
如果循环结束后,还有链表未被完全遍历(即还有剩余节点),这些剩余节点将直接接到新链表的末尾。注意,这里的第二个
if
语句实际上是不必要的,因为第一个if
已经处理了pHead1
不为空的情况,而pHead2
只有在pHead1
为空时才会不为空(因为两个链表都是递增的,所以一旦一个链表被遍历完,另一个链表中的所有剩余节点都将大于已经遍历完的链表中的所有节点)。因此,通常只需要保留第一个if
语句即可。但保留两个if
语句也不会导致错误,只是第二个if
在正常情况下永远不会被执行。 -
返回合并后的链表头节点:
return dummy.next;
最后,返回哨兵节点的下一个节点作为合并后链表的头节点。由于哨兵节点只是用作占位符,所以它的下一个节点才是合并后链表的真正头节点。
注意事项
- 哨兵节点的使用简化了链表头部可能为空的情况的处理。
- 在处理剩余节点时,通常只需要考虑一个链表即可,因为两个链表都是递增的。
- 确保在合并过程中正确更新链表指针,以避免内存泄漏或形成环形链表。