【发布时间】:2022-01-25 16:53:30
【问题描述】:
考虑在保持顺序的同时合并两个已排序的链表的问题。例如如果
L1: 1->1->2->4
和
L2: 2->3->5
那么结果应该是1->1->2->2->3->4->5。在 Elements of Programming Interview 中,作者提出了以下 Java 解决方案,包括遍历两个列表并选择最小的值添加到虚拟头中:
public static ListNode <Integer> mergeTwoSortedList s (ListNode <Integer> LI,
ListNode <Integer> L2) { // Creates a placeholder for the result.
ListNode <Integer> dummyHead = new ListNode<>(® , null);
ListNode <Integer> current = dummyHead;
ListNode <Integer> p1 = L1 , p2 = L2 ;
while (p1 != null && p2 != null) {
if (p1.data <= p2.data) {
current.next = p1;
p1 = p1.next ;
} else {
current.next = p2 ;
p2 = p2.next ;
}
current = current.next ;
}
// Appends the remaining nodes of p1 or p2.
current.next = p1 != null ? p1 : p2 ;
return dummy head.next ;
}
然后作者指出,这个解决方案在空间上是 O(1),因为它没有创建任何额外的节点。
我在 Python 中实现了一个非常相似的解决方案,但我注意到以下问题存在(同样适用于 p2):
current.next = p1
p1 = p1.next
我注意到,在 Python 中,在这种情况下,解决方案无法更新第二行中 p1 的值,同时也会更改上面一行中 current.next 的值(即第一行是浅拷贝),从而使结果列表为无(相当于空指针)。通过将第一行替换为
,可以在 python 中找到一个可行的解决方案current.next = NewNode(p1.val,None)
NewNode 创建一个与 p1 具有相同值的新节点和一个指向 None 的下一个“指针”。但是,这显然会利用 O(m+n) 空间,其中 m 和 n 是两个列表的长度。
但这让我质疑 Java 代码中 if 块中的整个语句。当我执行 current.next = p1 时,我是否没有创建列表的(深层)副本并因此使用额外的空间?在这种情况下,空间复杂度怎么会是 O(1)?我从更算法的角度理解 O(1) 空间声明的来源,但我没有看到这在代码中实现。如果 p1 = p1.next 不更新 current 的值,则它们之间肯定存在差异,因此必须进行深层复制,但这意味着额外的空间。我错过了什么?
【问题讨论】:
标签: python java linked-list complexity-theory space-complexity