leetcode25:K个一组翻转链表

题目链接

leetcode

题目描述

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

C++ 代码

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <iostream>
#include <vector>
using namespace std;

// 链表结点的定义
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) {}
};

// 辅助函数:创建链表
ListNode* createList(const vector<int>& nums) {
ListNode* dummy = new ListNode(-1);
ListNode* cur = dummy;
for (int num : nums) {
cur->next = new ListNode(num);
cur = cur->next;
}
return dummy->next;
}

// 辅助函数:打印链表
void printList(ListNode* head) {
while (head != nullptr) {
cout << head->val;
if (head->next != nullptr) cout << " -> ";
head = head->next;
}
}

// 辅助函数:释放链表内存
void deleteList(ListNode* head) {
while (head != nullptr) {
ListNode* temp = head;
head = head->next;
delete temp;
}
}

/*
递归实现

子问题(后面这部分链表)和原问题(整条链表)的结构完全相同,这就是递归性质。
1.反转以 head 开头的 k 个元素。
2.将第 k+1 个元素作为 head,递归调用 reverseKGroup 函数。
3.将上述两个过程的结果连接起来。

时间复杂度:O(n)
设链表长度为 N,将链表分成 N/k 个长度为 k 的子链表。
每个子链表翻转操作的时间是 O(k),总的时间复杂度是 O(N)。
空间复杂度:O(n)
递归调用会使用到栈空间,空间复杂度取决于链表的长度,即 O(N)。
此外,没有使用额外的空间(除了输出结果),总的空间复杂度是 O(N)。
*/
class Solution_0 {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if (head == nullptr || k == 0) {
return head;
}

// 找到这一组 k 个节点的首尾节点
ListNode *start = head, *end = head;
for (int i = 0; i < k; i++) {
if (end == nullptr) {
return head;
}
end = end->next;
}

// 反转这一组节点 [start, end)
ListNode *prev = nullptr, *cur = start;
while (cur != end) {
ListNode* temp = cur->next;
cur->next = prev;
prev = cur;
cur = temp;
}

// 递归调用,反转后面的链表并连接
start->next = reverseKGroup(end, k);
return prev;
}
};

/*
迭代实现

时间复杂度:O(n)
空间复杂度:O(1)
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if (head == nullptr || k == 0) {
return head;
}

ListNode* dummy = new ListNode();
dummy->next = head;
ListNode* prevEnd = dummy;

while (prevEnd != nullptr) {
// 找到这一组 k 个节点的首尾节点
ListNode *start = prevEnd->next, *end = prevEnd;
for (int i = 0; i < k && end != nullptr; i++) {
end = end->next;
}
if (end == nullptr) {
break;
}

// 反转这一组节点 [start, end]
ListNode* nextStart = end->next;
ListNode *prev = nullptr, *cur = start;
while (cur != nextStart) {
ListNode* temp = cur->next;
cur->next = prev;
prev = cur;
cur = temp;
}

// 连接反转后的子链表
start->next = nextStart;
prevEnd->next = end;
prevEnd = start;
}

return dummy->next;
}
};

int main() {
Solution solution;
vector<vector<int>> head_cases = {
{1,2,3,4,5},
{1,2,3,4,5},
{},
};
vector<int> k_cases = { 2, 3, 0 };

for (size_t i = 0; i < head_cases.size(); i++) {
auto& nums = head_cases[i];
int k = k_cases[i];

ListNode* head = createList(nums);
cout << "Input List: ";
printList(head);
cout << ", k = " << k << endl;

ListNode* result = solution.reverseKGroup(head, k);
cout << "Output List: ";
printList(result);
cout << endl;
}

return 0;
}

leetcode25:K个一组翻转链表
https://lcf163.github.io/2023/10/02/leetcode25:K个一组翻转链表/
作者
乘风的小站
发布于
2023年10月2日
许可协议