介绍:
欢迎来到另一个令人兴奋的 LeetCode 问题探索!在本文中,我们将深入探讨第 24 题问题:两两交换链表中的节点。我们将探讨问题陈述,讨论一种直观的解决方法,并提供解决方案的逐步细分。到最后,你将清楚地了解如何交换链表中的节点。让我们开始吧!
问题陈述:
给定一个链表,我们的任务是交换相邻的节点对。目标是重新排列链表,使得每一对节点都被交换,从而得到一种新的排列方式。需要注意的是,我们不应该修改节点中的值,而是重新排列节点本身。
例如,给定链表:1 -> 2 -> 3 -> 4,我们应该将其重新排列为:2 -> 1 -> 4 -> 3。
解决方法:
为了高效地解决这个问题,我们可以使用递归方法。通过递归交换相邻的节点对,我们可以有效地重新排列链表。
伪代码:
让我们来看一下我们递归方法的伪代码:
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
# Base case: Empty list or single node
if not head or not head.next:
return head
# Swapping the nodes
first = head
second = head.next
# Recursive call to swap the remaining list
first.next = self.swapPairs(second.next)
second.next = first
# Returning the new head of the swapped list
return second
详细解释:
- 我们定义一个
swapPairs
函数,该函数以链表的头部作为参数并返回重新排列的列表的头部。 - 我们从基本情况开始:如果列表为空或只包含一个节点,则我们只需返回头部,因为没有节点可交换。
- 接下来,我们初始化两个指针
first
和second
,以跟踪要交换的节点。我们将first
分配为当前头部,second
分配为下一个节点。 - 我们对
second.next
进行递归调用,以交换剩余部分的列表。这个递归调用处理了剩余列表中的一对一对交换。 - 在递归调用之后,我们通过将
first.next
设置为递归调用的结果(对应于已交换的剩余列表)来重新排列当前的一对。然后,我们将second.next
更新为first
,有效地交换了这两个节点。 - 最后,我们返回
second
作为重新排列的列表的新头,因为它现在占据了原始的first
节点的位置。
复杂度分析:
- 时间复杂度:递归解决方案的时间复杂度为 O(n),其中 n 是链表中节点的数量。每个节点在递归调用期间只被访问一次。
- 空间复杂度:由于考虑了递归调用堆栈,因此空间复杂度也为 O(n)。在最坏的情况下,递归深度等于列表中的节点数。
解决方案
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:
def getLength(head: ListNode) -> int:
length = 0
while head:
length += 1
head = head.next
return length
length = getLength(head)
dummy = ListNode(0, head)
prev = dummy
curr = head
for _ in range(length // 2):
next = curr.next
curr.next = next.next
next.next = prev.next
prev.next = next
prev = curr
curr = curr.next
return dummy.next
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
final int length = getLength(head);
ListNode dummy = new ListNode(0, head);
ListNode prev = dummy;
ListNode curr = head;
for (int i = 0; i < length / 2; ++i) {
ListNode next = curr.next;
curr.next = next.next;
next.next = curr;
prev.next = next;
prev = curr;
curr = curr.next;
}
return dummy.next;
}
private int getLength(ListNode head) {
int length = 0;
for (ListNode curr = head; curr != null; curr = curr.next)
++length;
return length;
}
}
C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
const int length = getLength(head);
ListNode dummy(0, head);
ListNode* prev = &dummy;
ListNode* curr = head;
for (int i = 0; i < length / 2; ++i) {
ListNode* next = curr->next;
curr->next = next->next;
next->next = prev->next;
prev->next = next;
prev = curr;
curr = curr->next;
}
return dummy.next;
}
private:
int getLength(ListNode* head) {
int length = 0;
for (ListNode* curr = head; curr; curr = curr->next)
++length;
return length;
}
};
结论:
在本文中,我们探讨了在链表中交换节点的问题。通过采用递归方法,我们成功地重新排列了列表,而不修改节点值。我们提供了解决方案的逐步细分,解释了伪代码的每个部分。
理解重新排列链表的艺术是处理数据结构和算法时非常有价值的技能。通过解决这样的问题,我们增强了解决问题的能力,并加强了对链表的理解。
记住,高效解决问题的关键是将其分解为更小、可管理的步骤。对于两两交换链表中的节点,递归提供了一种优雅的解决方案。通过递归交换对并重新排列列表,我们实现了预期的结果。
在你继续你的编码和算法问题解决之旅时,练习和巩固你对不同数据结构的理解是至关重要的。链表特别基础并广泛用于各种应用。
如果你喜欢这个问题并想进一步提高你的技能,我鼓励你探索与链表相关的其他 LeetCode 问题。通过挑战自己,面对各种场景,你将变得更加自信,可以在实际场景中解决类似的问题。
记住,熟能生巧,解决的问题越多,你的能力就越强。所以继续编码、继续学习、继续磨练你的问题解决技能。
评论(0)