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