基础知识要求:
Java:方法、while循环、if else语句、构造器函数、逻辑运算符
Python: 方法、while循环、if else语句、构造器函数、逻辑运算符
数据结构:链表
题目:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
提示:
- 两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
l1
和l2
均按 非递减顺序 排列
思路解析:
- 定义链表节点:
- 链表节点包含两个主要部分:一个存储数据的变量(如整数)和一个指向下一个节点的指针。
- 初始化:
- 创建一个哑节点(dummy head)作为新链表的起点,它不存储实际数据,但能帮助我们处理边界情况。
- 初始化一个指针(如
current
)指向哑节点,用于构建新链表。
- 合并过程:
- 使用两个指针(如
l1
和l2
)分别指向两个链表的头节点。 - 比较
l1
和l2
所指向节点的值,将较小的节点接到current
的next
,然后移动相应的链表指针和current
指针。 - 重复这个过程,直到其中一个链表遍历完。
- 使用两个指针(如
- 处理剩余节点:
- 如果某个链表还有剩余节点(即某个指针不为
null
),直接将剩余部分接到新链表的末尾。
- 如果某个链表还有剩余节点(即某个指针不为
- 返回结果:
- 返回哑节点的下一个节点,即合并后链表的头节点。
这个思路的关键在于利用两个指针来同时遍历两个链表,通过比较节点值来决定哪个节点应该被添加到新链表中。同时,通过哑节点来简化链表的头节点操作。整个合并过程只需要遍历两个链表一次,因此时间复杂度是线性的。
Java代码示例:
// 定义链表节点的数据结构
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
// 合并两个升序链表为一个新的升序链表
public class MergeTwoLists {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
// 创建一个哑节点作为新链表的头节点的前置节点
ListNode dummy = new ListNode(0);
// 创建一个指针current,用于构建新链表
ListNode current = dummy;
// 当l1和l2都不为空时,比较它们的值
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
// 如果l1的当前节点值小于等于l2的当前节点值,则将l1的当前节点接到新链表后面
current.next = l1;
l1 = l1.next; // 移动l1的指针
} else {
// 否则,将l2的当前节点接到新链表后面
current.next = l2;
l2 = l2.next; // 移动l2的指针
}
// 移动current指针到下一个位置
current = current.next;
}
// 如果l1还有剩余节点,将其接到新链表的末尾
if (l1 != null) {
current.next = l1;
}
// 如果l2还有剩余节点,将其接到新链表的末尾
if (l2 != null) {
current.next = l2;
}
// 哑节点的下一个节点是新链表的头节点
return dummy.next;
}
// 辅助方法:用于打印链表
public void printList(ListNode head) {
ListNode current = head;
while (current != null) {
System.out.print(current.val + " ");
current = current.next;
}
System.out.println();
}
// 示例代码
public static void main(String[] args) {
MergeTwoLists merger = new MergeTwoLists();
// 创建示例链表l1
ListNode l1 = new ListNode(1);
l1.next = new ListNode(2);
l1.next.next = new ListNode(4);
// 创建示例链表l2
ListNode l2 = new ListNode(1);
l2.next = new ListNode(3);
l2.next.next = new ListNode(4);
// 合并链表
ListNode mergedList = merger.mergeTwoLists(l1, l2);
// 打印合并后的链表
merger.printList(mergedList);
}
}
在上面的代码中,我们定义了一个ListNode
类来表示链表节点,并在MergeTwoLists
类中实现了mergeTwoLists
方法来合并两个链表。我们还提供了一个辅助方法printList
用于打印链表的值。在main
方法中,我们创建了示例链表l1
和l2
,然后调用mergeTwoLists
方法合并它们,并使用printList
方法打印出合并后的链表。
Python代码示例:
# 定义链表节点的数据结构
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
# 合并两个升序链表为一个新的升序链表
def mergeTwoLists(l1: ListNode, l2: ListNode) -> ListNode:
# 创建一个哑节点作为新链表的头节点的前置节点
dummy = ListNode(0) # dummy节点不存储实际数据,仅用于简化操作
# 创建一个指针current,用于构建新链表
current = dummy
# 当l1和l2都不为空时,比较它们的值
while l1 and l2:
if l1.val <= l2.val:
# 如果l1的当前节点值小于等于l2的当前节点值,则将l1的当前节点接到新链表后面
current.next = l1
l1 = l1.next # 移动l1的指针
else:
# 否则,将l2的当前节点接到新链表后面
current.next = l2
l2 = l2.next # 移动l2的指针
# 移动current指针到下一个位置
current = current.next
# 如果l1还有剩余节点,将其接到新链表的末尾
if l1:
current.next = l1
# 如果l2还有剩余节点,将其接到新链表的末尾
if l2:
current.next = l2
# 哑节点的下一个节点是新链表的头节点
return dummy.next
# 示例代码
# 创建示例链表l1
l1 = ListNode(1)
l1.next = ListNode(2)
l1.next.next = ListNode(4)
# 创建示例链表l2
l2 = ListNode(1)
l2.next = ListNode(3)
l2.next.next = ListNode(4)
# 合并链表
merged_list = mergeTwoLists(l1, l2)
# 打印合并后的链表
current = merged_list
while current:
print(current.val, end=' ')
current = current.next
# 输出应该是: 1 1 2 3 4 4
上面的代码首先定义了一个ListNode
类来表示链表节点,然后定义了一个mergeTwoLists
函数来合并两个升序链表。在mergeTwoLists
函数中,我们使用了一个哑节点dummy
来简化头节点的处理。然后我们使用两个指针l1
和l2
来遍历两个链表,并通过比较它们的值来决定哪个节点应该被添加到新链表中。最后,如果其中一个链表还有剩余节点,我们直接将它们连接到新链表的末尾。最后,我们返回哑节点的下一个节点,它实际上是新链表的头节点。
在示例代码中,我们创建了两个示例链表l1
和l2
,并将它们合并为一个新的链表,然后打印出合并后的链表的值。