题目
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即只能进行节点交换)。示例如下:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
解决思路
- 两两交换链表中的节点,即两个节点作为一组进行交换,依次下去直到结束。
- 两个节点作为一组进行交换,即k个一组翻转单链表中k等于2的特殊情况。k个一组翻转单链表方法见如下博文:参考这里
- 综上,两两交换链表中的节点即k个一组翻转单链表中k=2的情况。
代码
- C++代码
# include <stdio.h>
struct ListNode {
int val;
ListNode *next;
ListNode(): val(0), next(nullptr) {}
ListNode(int val): val(val), next(nullptr) {}
ListNode(int val, ListNode *next): val(val), next(next) {}
};
class Solution {
public:
// 真正进行链表反转的操作(递归法反转单链表)
ListNode *trueReverseN(ListNode *head, int k) {
if (nullptr == head || nullptr == head->next || 0 == k || 1 == k) {
return head;
}
ListNode *cur = head->next; // 指向头节点的下一个节点
ListNode *pre; // pre指向反转后链表的头结点
pre = trueReverseN(cur, k - 1); // 先递归到链表的最后一个节点。
head->next = cur->next; // 然后改变指针的指向。
cur->next = head;
cur = cur->next;
return pre;
}
// 先判断链表的长度够不够k个节点,如果够再进行反转。
ListNode *reverseN(ListNode *head, int k) {
if (nullptr == head || nullptr == head->next || 0 == k || 1 == k) {
return head;
}
int cnt = k;
ListNode *p = head;
// 判断链表的长度够不够k个节点。
while (--k && p) {
p = p->next;
}
if (nullptr == p) { // 说明不够k个节点
return head;
}
// 当链表节点够k个节点时,才进行真正的反转链表的操作。
return trueReverseN(head, cnt);
}
ListNode* swapPairs(ListNode* head) {
if (nullptr == head || nullptr == head->next) {
return head;
}
int k = 2;
ListNode ret(0, head); // 虚拟头节点
ListNode *p = &ret; // 初始时刻将指针p指向虚拟头节点,p节点的下一个节点即要进行反转部分链表的第一个节点。
ListNode *q = p->next; // 初始时刻q指针指向要进行反转部分链表的第一个节点,反转后q指针指向反转部分链表的尾结点。
// (p->next = reverseN(q, k)) != q:如果反转后返回的节点不为q节点,则说明反转成功。
// 循环调用“递归法反转链表”
while ((p->next = reverseN(q, k)) != q) {
p = q;
q = q->next;
}
return ret.next;
}
};
int main() {
ListNode *a = new ListNode(1);
ListNode *b = new ListNode(2);
ListNode *c = new ListNode(3);
ListNode *d = new ListNode(4);
ListNode *head = a;
a->next = b;
b->next = c;
c->next = d;
printf("before reverse: ");
while (head) {
printf("%d ", head->val);
head = head->next;
}
printf("\n");
head = a;
int k = 2;
Solution *solution = new Solution();
ListNode *ret = solution->swapPairs(head);
printf("after rverse: ");
while (ret) {
printf("%d ", ret->val);
ret = ret->next;
}
return 0;
}
- python代码
# -*- coding: utf-8 -*-
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
# 真正进行链表反转的操作(递归法反转单链表)。
def trueReverseN(self, head: ListNode, k: int) -> ListNode:
if not head or not head.next or 0 == k or 1 == k:
return head
cur: ListNode = head.next # 指向头节点的下一个节点。
# pre指向反转后链表的头结点。
# 先递归到链表的最后一个节点。
# 然后改变指针的指向。
pre: ListNode = self.trueReverseN(cur, k - 1)
head.next = cur.next
cur.next = head
cur = cur.next
return pre
# 先判断链表的长度够不够k个节点,如果够再进行反转。
def reverseN(self, head: ListNode, k: int) -> ListNode:
if not head or not head.next or 0 == k or 1 == k:
return head
cnt: int = k
p: ListNode = head
# 判断链表的长度够不够k个节点。
while k > 1 and p:
p = p.next
k -= 1
# 说明不够k个节点
if not p:
return head
# 当链表节点够k个节点时,才进行真正的反转链表的操作。
return self.trueReverseN(head, cnt)
def swapPairs(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
k: int = 2
ret: ListNode = ListNode(0, head) # 虚拟头节点
p: ListNode = ret # 初始时刻将指针p指向虚拟头节点,p节点的下一个节点即要进行反转部分链表的第一个节点。
q: ListNode = p.next # 初始时刻q指针指向要进行反转部分链表的第一个节点,反转后q指针指向反转部分链表的尾结点。
# (p->next = reverseN(q, k)) != q:如果反转后返回的节点不为q节点,则说明反转成功。
# 循环调用“递归法反转链表”
while True:
p.next = self.reverseN(q, k)
if p.next != q:
p = q
q = q.next
else:
break
return ret.next
def main():
a: ListNode = ListNode(1)
b: ListNode = ListNode(2)
c: ListNode = ListNode(3)
d: ListNode = ListNode(4)
head: ListNode = a
a.next = b
b.next = c
c.next = d
print("before reverse: ", end=' ')
while head:
print(head.val, end=' ')
head = head.next
print()
head = a
solution: Solution = Solution()
ret: ListNode = solution.swapPairs(head)
print("after reverse: ", end='')
while ret:
print(ret.val, end=' ')
ret = ret.next
if __name__ == "__main__":
main()
说明
- 对应LeetCode第24题。
- 链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs/