【问题标题】:how do I swap adjacent nodes in a linked-list with recursion?如何使用递归交换链表中的相邻节点?
【发布时间】:2021-07-15 07:00:38
【问题描述】:

我对以下 Leetocde 问题有一个解决方案: https://leetcode.com/problems/swap-nodes-in-pairs/

简单来说就是交换链表中的相邻节点。

def swapPairs(self, head: ListNode) -> ListNode:

    if not head or not head.next:
        return head

    # Nodes to be swapped
    first_node = head
    second_node = head.next

    # Swapping
    first_node.next  = self.swapPairs(second_node.next)
    second_node.next = first_node

    # Now the head is the second node
    return second_node

我正在努力实现对输入的递归,所以假设我们有输入节点 N1、N2、N3、N4。

当我们应用递归函数时,我得到:

N1 ->SwapPair(N3) ; with second_node = N2 
N3->None ; with second_node = N4

然后当我们解开它时,我得到:

N2-> N1-> N3 ->N4 

正确答案当然是N2-> N1-> N4 ->N3

我不太明白 N1 是如何连接到 N4 的 - 有什么想法吗?

【问题讨论】:

  • 尝试考虑使用虚拟节点(点对头)来提供帮助。并根据逻辑绘制图表..
  • 以上是我在逻辑上的尝试,但我看不出它是如何首先结合在一起的——尤其是 N1->N4
  • 运行你的代码,它很好,得到了正确的结果。不确定这里是否缺少某些东西。
  • 丹尼尔,我知道这是正确的,但正如我在问题中提到的那样,我很难理解其中的部分内容。

标签: recursion linked-list


【解决方案1】:

这可能有助于想象您给出的示例会发生什么。重要的是要意识到这个递归函数的每个执行上下文都有自己的一组局部变量。尽管不同的执行上下文的变量名称相同,但它们是不同的。

在主调用中我们有:

 head
  ↓
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  
│ val: 1  │  │ val: 2  │  │ val: 3  │  │ val: 4  │
│ next: ───> │ next: ───> │ next: ───> │ next: ───> None
└─────────┘  └─────────┘  └─────────┘  └─────────┘
  ↑            ↑ 
first_node    second_node

然后递归调用发生,它有自己的变量(名称相同,但它们不同):

                           head
                            ↓
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  
│ val: 1  │  │ val: 2  │  │ val: 3  │  │ val: 4  │
│ next: ───> │ next: ───> │ next: ───> │ next: ───> None
└─────────┘  └─────────┘  └─────────┘  └─────────┘
                            ↑            ↑ 
                           first_node   second_node

这里有一个更深层次的递归调用,它又有自己的head变量None

                                                    head
                                                     ↓
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  
│ val: 1  │  │ val: 2  │  │ val: 3  │  │ val: 4  │
│ next: ───> │ next: ───> │ next: ───> │ next: ───> None
└─────────┘  └─────────┘  └─────────┘  └─────────┘

...它从第一个 if 块返回 None

剩余的递归调用取回这个None返回值并将其分配给first_node.next

                           head
                            ↓
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
│ val: 1  │  │ val: 2  │  │ val: 3  │  │ val: 4  │
│ next: ───> │ next: ───> │ next: ───┐ │ next: ───> None
└─────────┘  └─────────┘  └─────────┘│ └─────────┘   ^
                            ↑        └───────────────┘ 
                           first_node    ↑ 
                                        second_node

然后second_node.next = first_node被执行:

                           head    ┌──────────────┐
                            ↓      V              │ 
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐│
│ val: 1  │  │ val: 2  │  │ val: 3  │  │ val: 4  ││
│ next: ───> │ next: ───> │ next: ───┐ │ next: ───┘   None
└─────────┘  └─────────┘  └─────────┘│ └─────────┘     ^
                            ↑        └─────────────────┘
                           first_node    ↑ 
                                        second_node

让我们重新排序最后两个节点的可视化,而不更改任何引用:

                                        head   
                                         ↓      
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
│ val: 1  │  │ val: 2  │  │ val: 4  │  │ val: 3  │
│ next: ───> │ next: ───┐ │ next: ───> │ next: ───> None
└─────────┘  └─────────┘│ └─────────┘  └─────────┘
                        │                ^
                        └────────────────┘
                            ↑            ↑                
                           second_node  first_node

然后second_node 从递归调用中返回,所以我们回到第一个执行上下文(带有它自己的局部变量),其中first_node.next 被分配了返回值:

 head      ┌────────────────┐
  ↓        │                V
┌─────────┐│ ┌─────────┐  ┌─────────┐  ┌─────────┐
│ val: 1  ││ │ val: 2  │  │ val: 4  │  │ val: 3  │
│ next: ───┘ │ next: ───┐ │ next: ───> │ next: ───> None
└─────────┘  └─────────┘│ └─────────┘  └─────────┘
                        │                ^
                        └────────────────┘
  ↑            ↑            ↑           
 first_node   second_node  returned

然后second_node.next = first_node被执行:

 head      ┌────────────────┐
  ↓        │                V
┌─────────┐│ ┌─────────┐  ┌─────────┐  ┌─────────┐
│ val: 1  ││ │ val: 2  │  │ val: 4  │  │ val: 3  │
│ next: ───┘ │ next: ───┐ │ next: ───> │ next: ───> None
└─────────┘  └─────────┘│ └─────────┘  └─────────┘
       ^                │
       └────────────────┘
  ↑            ↑
 first_node   second_node  

让我们在不更改引用的情况下再次重新排序可视化:

              head
               ↓
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  
│ val: 2  │  │ val: 1  │  │ val: 4  │  │ val: 3  │
│ next: ───> │ next: ───> │ next: ───> │ next: ───> None
└─────────┘  └─────────┘  └─────────┘  └─────────┘
  ↑            ↑
 second_node  first_node  

最后,second_node 作为新的头部返回。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-23
    相关资源
    最近更新 更多