按排序顺序合并 2 个链表

merge 2 linked lists in sorted order

合并两个排序的链表并return它作为一个排序的列表。该列表应通过将前两个列表的节点拼接在一起来制作。

我们有 l1:

ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 4, next: None}}}

和 l2:

ListNode{val: 1, next: ListNode{val: 3, next: ListNode{val: 4, next: None}}}

我使用以下代码合并它们:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        print(l1)
        print(l2)
        out = ListNode(-1)
        temp = out
        while l1 and l2:
            if (l1.val < l2.val):
                temp.next = l1
                l1 = l1.next
            else:
                temp.next = l2
                l2 = l2.next
            temp = temp.next
        print(out)

结果是这样的:

ListNode{val: -1, next: ListNode{val: 1, next: ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 3, next: ListNode{val: 4, next: None}}}}}}

我的问题是 out 是如何更新的?

outwhile 循环的第一次迭代中发生变异。

想象一下可能会有所帮助。

就在循环开始之前,我们创建了一个虚拟节点(值为 -1)并用 outtemp:

引用它
                   l1
                   ↓
                 ┌────────────┐    ┌────────────┐    ┌────────────┐
                 │ data: 1    │    │ data: 2    │    │ data: 4    │
                 │ next: ────────> │ next: ────────> │ next: None │
 out             └────────────┘    └────────────┘    └────────────┘
  ↓
┌────────────┐
│ data: -1   │
│ next: None │
└────────────┘
  ↑
 temp            ┌────────────┐    ┌────────────┐    ┌────────────┐
                 │ data: 1    │    │ data: 3    │    │ data: 4    │
                 │ next: ────────> │ next: ────────> │ next: None │
                 └────────────┘    └────────────┘    └────────────┘
                   ↑
                   l2

在第一次迭代中,我们进入 else 块,其中 temp 变异的 。由于 tempout 引用同一个对象,这会改变 out.

                   l1
                   ↓
                 ┌────────────┐    ┌────────────┐    ┌────────────┐
                 │ data: 1    │    │ data: 2    │    │ data: 4    │
                 │ next: ────────> │ next: ────────> │ next: None │
 out             └────────────┘    └────────────┘    └────────────┘
  ↓
┌────────────┐
│ data: -1   │
│ next: ──────┐
└────────────┘│
  ↑           │
 temp         │  ┌────────────┐    ┌────────────┐    ┌────────────┐
              │  │ data: 1    │    │ data: 3    │    │ data: 4    │
              └> │ next: ────────> │ next: ────────> │ next: None │
                 └────────────┘    └────────────┘    └────────────┘
                   ↑
                   l2

这次更新后,l2temp 都被“移动”以指代他们的继任者。第一次迭代到此结束:

                   l1
                   ↓
                 ┌────────────┐    ┌────────────┐    ┌────────────┐
                 │ data: 1    │    │ data: 2    │    │ data: 4    │
                 │ next: ────────> │ next: ────────> │ next: None │
 out             └────────────┘    └────────────┘    └────────────┘
  ↓
┌────────────┐
│ data: -1   │
│ next: ──────┐
└────────────┘│
              │
              │  ┌────────────┐    ┌────────────┐    ┌────────────┐
              │  │ data: 1    │    │ data: 3    │    │ data: 4    │
              └> │ next: ────────> │ next: ────────> │ next: None │
                 └────────────┘    └────────────┘    └────────────┘
                   ↑                 ↑
                  temp               l2

我们真的不必继续执行该算法,因为从现在开始 out 不会再次发生变异:这项工作已经完成。但是,让我们再继续一次迭代(第二次迭代)。我们进入 if 块,temp 再次发生变异(但这一次,它不是 out 的同义词):

                   l1
                   ↓
                 ┌────────────┐    ┌────────────┐    ┌────────────┐
                 │ data: 1    │    │ data: 2    │    │ data: 4    │
              ┌> │ next: ────────> │ next: ────────> │ next: None │
 out          │  └────────────┘    └────────────┘    └────────────┘
  ↓           └────────────────┐
┌────────────┐                 │
│ data: -1   │                 │
│ next: ──────┐                │
└────────────┘│                │
              │                │
              │  ┌────────────┐│   ┌────────────┐    ┌────────────┐
              │  │ data: 1    ││   │ data: 3    │    │ data: 4    │
              └> │ next: ──────┘   │ next: ────────> │ next: None │
                 └────────────┘    └────────────┘    └────────────┘
                   ↑                 ↑
                  temp               l2

...并且 l1temp 都移至他们的继任者:

                  temp               l1
                   ↓                 ↓
                 ┌────────────┐    ┌────────────┐    ┌────────────┐
                 │ data: 1    │    │ data: 2    │    │ data: 4    │
              ┌> │ next: ────────> │ next: ────────> │ next: None │
 out          │  └────────────┘    └────────────┘    └────────────┘
  ↓           └────────────────┐
┌────────────┐                 │
│ data: -1   │                 │
│ next: ──────┐                │
└────────────┘│                │
              │                │
              │  ┌────────────┐│   ┌────────────┐    ┌────────────┐
              │  │ data: 1    ││   │ data: 3    │    │ data: 4    │
              └> │ next: ──────┘   │ next: ────────> │ next: None │
                 └────────────┘    └────────────┘    └────────────┘
                                     ↑
                                     l2

继续这样,temp 将保留正在连接的结果列表的尾部。在最后一次迭代之后,我们将得到:

                                                       l1
                                                       ↓
                 ┌────────────┐    ┌────────────┐    ┌────────────┐
                 │ data: 1    │    │ data: 2    │    │ data: 4    │
              ┌> │ next: ────────> │ next: ──────┐   │ next: None │
 out          │  └────────────┘    └────────────┘│   └────────────┘
  ↓           └────────────────┐ ┌───────────────┘
┌────────────┐                 │ │                                
│ data: -1   │                 │ │                                
│ next: ──────┐                │ │                                
└────────────┘│                │ │                                
              │                │ │                                
              │  ┌────────────┐│ │ ┌────────────┐    ┌────────────┐
              │  │ data: 1    ││ │ │ data: 3    │    │ data: 4    │
              └> │ next: ──────┘ └>│ next: ────────> │ next: None │
                 └────────────┘    └────────────┘    └────────────┘
                                                       ↑                
                                                      temp

这项工作尚未完全完成,因为您发布的代码段中缺少一些代码。当 while 循环退出时,l1l2 之一将不是 None,这表示仍然需要附加到结果列表的部分。由于 temp 指的是结果列表的当前尾部,我们应该将其 next 引用设置为 l1l2 —— 以不是 None 的那个为准。

所以代码在循环后应该有类似下面的语句:

temp.next = l1 or l2

...结果是:

                                                       l1
                                                       ↓
                 ┌────────────┐    ┌────────────┐    ┌────────────┐
                 │ data: 1    │    │ data: 2    │    │ data: 4    │
              ┌> │ next: ────────> │ next: ──────┐ ┌>│ next: None │
 out          │  └────────────┘    └────────────┘│ │ └────────────┘
  ↓           └────────────────┐ ┌───────────────┘ └───────────────┐
┌────────────┐                 │ │                                 │
│ data: -1   │                 │ │                                 │
│ next: ──────┐                │ │                                 │
└────────────┘│                │ │                                 │
              │                │ │                                 │
              │  ┌────────────┐│ │ ┌────────────┐    ┌────────────┐│
              │  │ data: 1    ││ │ │ data: 3    │    │ data: 4    ││
              └> │ next: ──────┘ └>│ next: ────────> │ next: ──────┘
                 └────────────┘    └────────────┘    └────────────┘
                                                       ↑                
                                                      temp

最后,函数应该 return 结果。由于 out 指的是一个虚拟节点,我们不应该只是 return out,而是 out.next:

return out.next

returned 列表引用将指向此:

           ┌────────────┐    ┌────────────┐    ┌────────────┐
           │ data: 1    │    │ data: 2    │    │ data: 4    │
        ┌> │ next: ────────> │ next: ──────┐ ┌>│ next: None │
        │  └────────────┘    └────────────┘│ │ └────────────┘
        └────────────────┐ ┌───────────────┘ └───────────────┐
                         │ │                                 │
           ┌────────────┐│ │ ┌────────────┐    ┌────────────┐│
           │ data: 1    ││ │ │ data: 3    │    │ data: 4    ││
returned → │ next: ──────┘ └>│ next: ────────> │ next: ──────┘
           └────────────┘    └────────────┘    └────────────┘

我希望这能说明问题。

如果有帮助,您甚至不需要任何临时节点。您可以重新链接现有节点,这会使其变得更加简单:

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if not (l1 and l2):
            return l1 or l2
        if l2.val < l1.val:
            l1, l2 = l2, l1
        l1.next = self.mergeTwoLists(l1.next, l2)
        return l1