问题描述
给你一个链表,每k个节点一组进行翻转,请你返回翻转后的链表。k是一个正整数,它的值小于或等于链表的长度。如果节点总数不是k的整数倍,那么请将最后剩余的节点保持原有的顺序。
举例
示例1: 输入:1->2->3->4->5 k=2 输出:2->1->4->3->5
示例2: 输入:1->2->3->4->5 k=3 输出:3->2->1->4->5
示例3: 输入:1->2->3->4->5 k=1 输出:1->2->3->4->5
示例4:输入: 1 k=1 输出:1
解题方法: 细节决定成败。三个注意点:1)引入哨兵虚拟头节点,可以避免讨论头指针是否为空;2)翻转[phead, ptail]过程中,要先保存好head的前一个指针和tail的next指针,从而避免链表断链;3)翻转后要及时更新pre, phead, ptail几个指针,直到指针遍历完。
代码
#include <iostream>
#include <memory> //std::shared_ptr
#include <utility> // std::pair
struct Node {
int value;
Node* next;
Node(int value) {
this->value = value;
next = nullptr; //这个千万别忘了,否则容易引发segment fault
}
};
Node* reverse(Node* head) {
Node* pre = nullptr;
Node* p = head;
while (p) {
auto next = p->next;
p->next = pre;
pre = p;
p = next;
}
return pre;
}
// 翻转[head, tail]的元素
std::pair<Node*, Node*> reverse(Node* head, Node* tail) {
if (head == nullptr || tail == nullptr) {
return {};
}
Node* pre = nullptr;
Node* p = head;
// 特别注意:
// 这里容易错写成while(p != tail->next),显然是错误的.
// 原因是tail对应的元素翻转后,tail->next不再指向原来的next,而是指向翻转后的next
// 除非提前将tail->next在循环外保存,例如:
// Node* tail_next = tail->next;
// while (p != tail_next) {...}
while (pre != tail) { // 这里容易错写成p != tail->next
Node* next = p->next;
p->next = pre;
pre = p;
p = next;
}
return {tail, head};
}
Node* reverse_k(Node* head, int k) {
std::shared_ptr<Node> dummy_node(new Node(-1));
dummy_node->next = head;
Node* pre = dummy_node.get();
Node* phead = head;
Node* ptail = pre;//从真正头节点前一个位置出发
while (phead) {
for (int i = 0; i < k; i++) {
ptail = ptail->next;
if (ptail == nullptr) { //长度不够k则直接返回
return dummy_node->next;
}
}
Node *next = ptail->next;//先保存tail的下一个位置,防止断链
auto reverse_ret = reverse(phead, ptail);//翻转[phead, ptail]区间
phead = reverse_ret.first;
ptail = reverse_ret.second;
// 更新连接
pre->next = phead;
ptail->next = next;
// 指针向前移动
pre = ptail;
phead = next;
}
return dummy_node->next;
}
void print_list(Node* head) {
Node* p = head;
while (p) {
std::cout << p->value << "->";
p = p->next;
}
std::cout << "nullptr" << std::endl;;
}
int main()
{
// case1: 1->2->3->4->5, k=2 ==> 2->1->4->3->5
Node n1(1),n2(2),n3(3),n4(4),n5(5);
n1.next = &n2;
n2.next = &n3;
n3.next = &n4;
n4.next = &n5;
Node* head = &n1;
print_list(head);
head = reverse_k(head, 2);
std::cout << "case1, k=2:" << std::endl;
print_list(head);
// case2: 1->2->3->4->5, k=3 ==> 3->2->1->4->5
n1.next = &n2;
n2.next = &n3;
n3.next = &n4;
n4.next = &n5;
head = &n1;
head = reverse_k(head, 3);
std::cout << "case2, k=3:" << std::endl;
print_list(head);
// case3: 1->2->3->4->5, k=1 ==> 1->2->3->4->5
n1.next = &n2;
n2.next = &n3;
n3.next = &n4;
n4.next = &n5;
head = &n1;
head = reverse_k(head, 1);
std::cout << "case3, k=1:" << std::endl;
print_list(head);
// case4: 1, k = 1
n1.next = nullptr;
head = &n1;
head = reverse_k(head, 1);
std::cout << "case3, list is 1->nullptr, k=1:" << std::endl;
print_list(head);
return 0;
}
代码运行结果如下:
1->2->3->4->5->nullptr
case1, k=2:
2->1->4->3->5->nullptr
case2, k=3:
3->2->1->4->5->nullptr
case3, k=1:
1->2->3->4->5->nullptr
case3, list is 1->nullptr, k=1:
1->nullptr