持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
25. K 个一组翻转链表
给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
解法
解法1 利用栈翻转
使用栈来帮助我们完成翻转链表这一过程,对于每k个位置,就将其拆开,然后利用栈来翻转其节点
用栈,我们把 k 个数压入栈中,弹出来的顺序就是翻转的序列
剩余翻转:
-
剩下的链表个数够不够 k 个 不会翻转;
-
翻转的部分要与左右链表连接起来。
总体时间复杂度,空间复杂度
代码1
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
stack<ListNode*> st;
auto cur = head;
auto t = ListNode(0, head);
auto pre = &t;
while (cur) {
st.push(cur);
if (st.size() == k) {
auto t = cur->next;
auto tm = pre->next;
pre->next = nullptr;
auto now = pre;
while (st.size()) {
auto t = st.top(); st.pop();
t->next = nullptr;
now->next = t;
now = t;
}
tm->next = t;
cur = tm;
pre = tm;
}
cur = cur->next;
}
return t.next;
}
};
解法2
上面的方法是利用栈来进行翻转,还是需要利用一定的空间,其实可以将这些空间优化掉。
但其实,链表有一种原地逆序的算法,那就是头插法~
每次将元素查到头部来即可
举个例子:
1 2 3 4 5
head-> 1
head-> 2 -> 1
head-> 3 -> 2 -> 1
head -> 4 -> 3 -> 2 -> 1
head -> 5 -> 4 -> 3 -> 2 -> 1
如同这样,将其插入进去
同样的,要注意一点,反转后的链表要和前面的连接起来
所以,这里最好再多使用一个辅助节点来帮忙完成这一件事情
总体时间复杂度,空间复杂度
代码
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
int cnt = 0;
auto cur = head;
auto tm = ListNode(0, head);
auto begin = &tm;
auto start = begin;
while (cur) {
cnt ++;
if (cnt == k) {
cnt = 0;
auto nex = cur->next;
cur->next = nullptr;
auto now = begin->next;
auto tmp = now;
begin->next = nullptr;
while (now) {
auto t = now->next;
now->next = begin->next;
begin->next = now;
now = t;
}
tmp->next = nex;
cur = tmp;
begin = cur;
}
cur = cur->next;
}
return start->next;
}
};