数据结构与算法之深入解析“两两交换链表中的节点”的求解思路与算法示例

Posted Serendipity·y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法之深入解析“两两交换链表中的节点”的求解思路与算法示例相关的知识,希望对你有一定的参考价值。

一、题目要求

  • 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
  • 示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]
  • 示例 2:
输入:head = []
输出:[]
  • 示例 3:
输入:head = [1]
输出:[1]
  • 提示:
    • 链表中节点的数目在范围 [0, 100] 内;
    • 0 <= Node.val <= 100。

二、求解算法

① 带虚拟头节点的单链表实现

  • 先建立一个带虚拟头节点的单链表:

# 链表节点类
class ListNode:
     def __init__(self, val=0, next=None):
         self.val = val
         self.next = next
# 创建虚拟节点
dummyHead = ListNode(-1)
  • 因为每次要截取两个节点进行交换,初始建立 3 个指针 pre,p 和 q。其中 pre 指向虚拟头节点,p 指向链表首节点,q 指向链表的第 2 个节点。

pre = dummyHead
p = head
q = p.next
  • 节点两两交换主要分为 3 步:
    • 第 1 步:pre 的后继指针 next 指向 q,即 pre.next = q:

    • 第 2 步:p 的后继指针 next 指向 q 的后继节点,即 p.next = q.next:

    • 第 3 步:那就剩了 q 的后继指针 next 指向 p,即 q.next = p:

  • 所以第一次交换完,链表变成了:

pre.next = q
p.next = q.next
q.next = p
  • 接下来就是 pre、p 和 q 指针同时右移:
pre = p
p = p.next
q = p.next
  • 继续重复上述 3 步操作:

  • Python 示例:
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:

        # 空链表或者只有一个节点,直接返回
        if not head or head.next == None:
            return head

        # 创建虚拟节点
        dummyHead = ListNode(-1)

        # 初始化pre、p 节点
        pre = dummyHead
        p = head

        # 必须是节点数是偶数个的时候才能交换
        # 如果最后只剩下一个节点,即链表是奇数个节点,最后一个不用反转
        # 比如 head = [1,2, 3, 4, 5],输出 [2, 1, 4, 3, 5]
        while p and p.next:
            # 初始化 q 节点
            q = p.next

            # 交换节点 3 步走
            pre.next = q
            p.next = q.next
            q.next = p
            
            # 指针右移
            pre = p
            p = p.next
        
        # 返回链表
        return dummyHead.next

② 递归

  • 可以通过递归的方式实现两两交换链表中的节点,递归的终止条件是链表中没有节点,或者链表中只有一个节点,此时无法进行交换。
  • 如果链表中至少有两个节点,则在两两交换链表中的节点之后,原始链表的头节点变成新的链表的第二个节点,原始链表的第二个节点变成新的链表的头节点。链表中的其余节点的两两交换可以递归地实现。在对链表中的其余节点递归地两两交换之后,更新节点之间的指针关系,即可完成整个链表的两两交换。
  • 用 head 表示原始链表的头节点,新的链表的第二个节点,用 newHead 表示新的链表的头节点,原始链表的第二个节点,则原始链表中的其余节点的头节点是 newHead.next。令 head.next = swapPairs(newHead.next),表示将其余节点进行两两交换,交换后的新的头节点为 head 的下一个节点。然后令 newHead.next = head,即完成了所有节点的交换。最后返回新的链表的头节点 newHead。
  • Java 示例:
class Solution 
    public ListNode swapPairs(ListNode head) 
        if (head == null || head.next == null) 
            return head;
        
        ListNode newHead = head.next;
        head.next = swapPairs(newHead.next);
        newHead.next = head;
        return newHead;
    

  • Python 示例:
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head
        newHead = head.next
        head.next = self.swapPairs(newHead.next)
        newHead.next = head
        return newHead

③ 迭代

  • 也可以通过迭代的方式实现两两交换链表中的节点。
  • 创建哑结点 dummyHead,令 dummyHead.next = head。令 temp 表示当前到达的节点,初始时 temp = dummyHead。每次需要交换 temp 后面的两个节点。
  • 如果 temp 的后面没有节点或者只有一个节点,则没有更多的节点需要交换,因此结束交换。否则,获得 temp 后面的两个节点 node1 和 node2,通过更新节点的指针关系实现两两交换节点。
  • 具体而言,交换之前的节点关系是 temp -> node1 -> node2,交换之后的节点关系要变成 temp -> node2 -> node1,因此需要进行如下操作。
temp.next = node2
node1.next = node2.next
node2.next = node1
  • 完成上述操作之后,节点关系即变成 temp -> node2 -> node1。再令 temp = node1,对链表中的其余节点进行两两交换,直到全部节点都被两两交换。
  • 两两交换链表中的节点之后,新的链表的头节点是 dummyHead.next,返回新的链表的头节点即可。



  • Python 示例:
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        dummyHead = ListNode(0)
        dummyHead.next = head
        temp = dummyHead
        while temp.next and temp.next.next:
            node1 = temp.next
            node2 = temp.next.next
            temp.next = node2
            node1.next = node2.next
            node2.next = node1
            temp = node1
        return dummyHead.next
  • Java 示例:
class Solution 
    public ListNode swapPairs(ListNode head) 
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode temp = dummyHead;
        while (temp.next != null && temp.next.next != null) 
            ListNode node1 = temp.next;
            ListNode node2 = temp.next.next;
            temp.next = node2;
            node1.next = node2.next;
            node2.next = node1;
            temp = node1;
        
        return dummyHead.next;
    

以上是关于数据结构与算法之深入解析“两两交换链表中的节点”的求解思路与算法示例的主要内容,如果未能解决你的问题,请参考以下文章

打卡算法 24两两交换链表中的节点 算法解析

打卡算法 24两两交换链表中的节点 算法解析

打卡算法 24两两交换链表中的节点 算法解析

☆打卡算法☆LeetCode 24两两交换链表中的节点 算法解析

LintCode之两两交换链表中的节点

Leetcode两两交换链表中的节点(24)