📅  最后修改于: 2023-12-03 15:07:34.556000             🧑  作者: Mango
这是一道关于数据结构的经典问题,主要考察了链表的基本操作。该问题涉及两个链表,给定它们的头结点,请将它们合并成一个新的有序链表。
给定两个升序排列的链表 L1
和 L2
,请把它们合并为一个有序的链表 L3
。例如:
L1: 1 -> 3 -> 5 -> 7
L2: 2 -> 4 -> 6 -> 8 -> 10
L3: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 10
这道题是一道比较经典的链表合并问题,可以按照以下步骤解决:
定义一个新的链表 L3
,并用一个指针 p
指向它的头结点。
分别用两个指针 p1
和 p2
分别指向链表 L1
和 L2
的头结点。
每次比较 p1
和 p2
指向的数据元素,将较小的那个放入 L3
中,并将相应的指针后移一位。
当其中一个链表被遍历完后,将另一个链表中剩余的元素直接加入 L3
中。
最后返回 L3
的头结点即可。
下面是该算法的示意图:
L1: 1 -> 3 -> 5 -> 7
L2: 2 -> 4 -> 6 -> 8 -> 10
|
↓
L3:
p
L1: 1 -> 3 -> 5 -> 7
L2: 2 -> 4 -> 6 -> 8 -> 10
|
↓
L3: 1
p
L1: 1 -> 3 -> 5 -> 7
L2: 2 -> 4 -> 6 -> 8 -> 10
|
↓
L3: 1 -> 2
p
L1: 3 -> 5 -> 7
L2: 2 -> 4 -> 6 -> 8 -> 10
|
↓
L3: 1 -> 2 -> 3
p
L1: 3 -> 5 -> 7
L2: 2 -> 4 -> 6 -> 8 -> 10
|
↓
L3: 1 -> 2 -> 3 -> 4
p
L1: 5 -> 7
L2: 2 -> 4 -> 6 -> 8 -> 10
|
↓
L3: 1 -> 2 -> 3 -> 4 -> 5
p
L1: 5 -> 7
L2: 2 -> 4 -> 6 -> 8 -> 10
|
↓
L3: 1 -> 2 -> 3 -> 4 -> 5 -> 6
p
L1: 5 -> 7
L2: 4 -> 6 -> 8 -> 10
|
↓
L3: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7
p
L1: 7
L2: 4 -> 6 -> 8 -> 10
|
↓
L3: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
p
L1: 7
L2: 6 -> 8 -> 10
|
↓
L3: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 10
p
L1:
L2: 6 -> 8 -> 10
|
↓
L3: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 10
p
下面是该算法的 Python 实现:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def merge_two_lists(l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode(-1)
p = dummy
while l1 and l2:
if l1.val <= l2.val:
p.next = l1
l1 = l1.next
else:
p.next = l2
l2 = l2.next
p = p.next
if l1:
p.next = l1
if l2:
p.next = l2
return dummy.next
其中 ListNode
是定义链表节点的类,merge_two_lists
是实现链表合并的函数,它接收两个链表的头结点 l1
和 l2
,返回合并后的链表的头结点。
在函数中,我们先定义了一个虚拟头结点 dummy
,并将指针 p
指向它。这里使用虚拟头结点的意义在于,最终返回的是真正链表的头结点的 next
。
接下来我们使用 while
循环遍历两个链表,每次将较小的节点加入到新的链表中,并将相应节点的指针向后移动一位。当其中一个链表被遍历完后,我们将另一个链表中剩余的节点都挂载到新链表的尾部。
最后,返回新链表的头结点即可。
链表结构虽然相对于数组来说更为灵活,但是其本身的特点也决定了其在使用时需要更为注意指针的操作,否则容易出现一些错误。这里再次强调算法步骤中需要注意指针的后移操作,避免出现指针漏移等错误。