反转链表问题
felicx 化神

一、反转链表(简)

题目

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例1:
1 -> 2 -> 3 -> 4 -> 5
—->
5 -> 4 -> 3 -> 2 -> 1
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例2:
1 -> 2
—->
2 -> 1
输入:head = [1,2]
输出:[2,1]

示例3:
输入:head = [ ]
输出:[ ]

提示:
链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000

题解1

迭代法,记录pre节点和cur节点,不断交换pre和cur,同时cur后移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = NULL;
ListNode* cur = head;

while (cur != NULL) {
ListNode* next = cur->next; // 这里到最后一个数字时没有next了,返回NULL
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};

题解2

递归法,假设链表其余部分已被反转,怎么去反转它前面的部分。
假设a->b->c->d->e->f->NULL;
若e->f已经被反转成e<-f,此时在d,我们希望将d->e变为d<-e,所以d->next->next=d;
这时d和e互相指向,要断开,所以d->next=NULL。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (!head || !head->next) {
return head;
}
ListNode* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}
};

二、反转链表Ⅱ(中)

题目

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

示例1:
1 -> 2 -> 3 -> 4 -> 5
—->
1 -> 4 -> 3 -> 2 -> 5
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例2:
输入:head = [5], left = 1, right = 1
输出:[5]

提示:
链表中节点数目为 n
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n

题解

首先,凡是链表题都可以创建个伪头节点,如下

1
2
ListNode* dummy = new ListNode(0);
dummy->next = head;

参考反转链表,这题是特定位置反转,可以根据left和right取出需要反转的链表,代入反转链表的解法进行反转,再和前后链表拼接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
public:
// 照搬反转链表
ListNode* reverseList(ListNode* head) {
ListNode* pre = NULL;
ListNode* cur = head;

while (cur != NULL) {
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}

ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode* dummy = new ListNode(0);
dummy->next = head;

ListNode* pre = dummy;
ListNode* end = dummy;

for (int i = 0; i < left - 1; i++)
pre = pre->next; // 要截取链表的头节点的前一个节点
ListNode* start = pre->next; // 要截取链表的头节点
for (int i = 0; i < right; i++)
end = end->next; // 要截取链表的尾节点
ListNode* next = end->next; // 要截取链表的尾节点的后一个节点
end->next = NULL; // 截断链表,才能用于反转
pre->next = reverseList(start);
start->next = next; // 链表拼接

return dummy->next;
}
};

三、K个一组翻转链表(困)

题目

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例1:
1 -> 2 -> 3 -> 4 -> 5
—->
2 -> 1 -> 4 -> 3 -> 5
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例2:
1 -> 2 -> 3 -> 4 -> 5
—->
3 -> 2 -> 1 -> 4 -> 5
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

示例3:
输入:head = [ ]
输出:[ ]

提示:
链表中的节点数目为 n
1 <= k <= n <= 5000
0 <= Node.val <= 1000

题解

参考反转链表Ⅱ,反转链表Ⅱ中是给定left和right进行截取来反转,这里可以通过遍历给定的链表,每k个截取一段链表,然后反转并拼接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
public:
// 照搬反转链表
ListNode* reverseList(ListNode* head) {
ListNode* pre = NULL;
ListNode* cur = head;

while (cur != NULL) {
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}

// 微调反转链表II
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummy = new ListNode(0);
dummy->next = head;

ListNode* pre = dummy;
ListNode* end = dummy;

while (end->next != NULL) {
ListNode* start = pre->next; // 要截取链表的头节点
for (int i = 0; i < k && end != NULL; i++)
end = end->next; // 要截取链表的尾节点
if (end == NULL)
break;
ListNode* next = end->next; // 要截取链表的尾节点的后一个节点
end->next = NULL; // 截断链表,才能用于反转
pre->next = reverseList(start);
start->next = next; // 链表拼接

// 开始下一次反转
pre = start;
end = pre;
}
return dummy->next;
}
};
 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep
访客数 访问量