假设存在有一个链表,每过m个节点设为一组,然后把他们进行翻转。
请你返回翻转后的链表。
说明:
- m是一个正整数,它的值<= 链表的长度
- 若是节点的总数不是m的不为m的整数倍,那么后面剩余的节点请保存原有顺序。
- 设计一个只是用常数额外空间的算法来解决此问题
- 不能只单纯改变节点内部的值。而需要实际进行节点的交互。
示例结果1:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例结果2:
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
示例结果3:
输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]
示例结果4:
输入:head = [1], k = 1
输出:[1]
设计思路:
第一步:找到小组里尾结点的指针->groupTail
第二步:遍历找到尾结点的前一个结点->prevTail
第三步:groupTail的next指针指向prevTail
groupTail指向prevTail,依次向前推进,重复以上操作…
最后:改变头节点的指向为尾节点的指向
代码如下:
/**************************************************************************
Author: YaoDemi
Date:2022-03-21
Description: Reverse the linkList by group
**************************************************************************/
#include <iostream>
using namespace std;
//Definition for singly-linked list.
struct LinkNode {
int val;
LinkNode* next;
LinkNode() : val(0), next(nullptr) {}
LinkNode(int x) : val(x), next(nullptr) {}
LinkNode(int x, LinkNode* next) : val(x), next(next) {}
};
// KLinkSolution -- linkList operation
class KLinkSolution {
private:
LinkNode* head; //头节点
LinkNode* tail; //尾结点
LinkNode* curr; //现在的位置
int cnt; //链表的大小
//初始话链表
void init()
{
curr = tail = head = new LinkNode();
cnt = 0;
}
//释放链表
void removeAll()
{
while (head != NULL) {
curr = head;
head = head->next;
delete curr;
}
}
public:
//构造函数
KLinkSolution() { init(); }
//析构函数
~KLinkSolution() { removeAll(); }
//清除链表
void clear() { removeAll();init(); }
//获取链表的头节点
//返回:头节点的指针
LinkNode* getHead() { return head; }
//获取链表的尾结点
//返回:尾结点的指针
LinkNode* getTail() { return tail; }
//在链表的末尾添加元素
void append(const int& it)
{
tail = tail->next = new LinkNode(it, NULL);
cnt++;
}
//获取链表节点的前一个节点
//参数:节点的指针node
//返回值:节点的前一个节点的指针
LinkNode* prevNode(LinkNode* node)
{
if (node == head) return node;
LinkNode* temp = head;
while (temp->next != node) temp = temp->next;
return temp;
}
//打印链表
void print() const
{
LinkNode* temp = head;
while (temp->next != NULL) {
temp = temp->next;
cout << temp->val << " ";
}
}
//反转一个小组的链表
//只用常数额外空间,用节点的交互的方法进行反转
//参数:当前小组的头指针groupHead,一个小组的节点数k
//返回:下一个小组的头指针
LinkNode* reverseKGroup(LinkNode* groupHead, int k) {
LinkNode* groupTail = groupHead; //小组的尾结点
LinkNode* prevHead = prevNode(groupHead); //小组头节点的前一个节点
for (int i = 1;i < k;i++) {
groupTail = groupTail->next;
}
LinkNode* nextHead = groupTail; //反转后头节点应该指向的节点,即现在的尾结点
LinkNode* nextGroup = groupTail->next; //下一个小组的头节点
//尾结点往前遍历反转
while (groupTail != groupHead)
{
LinkNode* prevTail = prevNode(groupTail);
groupTail->next = prevTail;
groupTail = prevTail;
}
prevHead->next = nextHead;
groupTail->next = nextGroup; //现在尾结点的位置是反转后尾结点的位置
return nextGroup;
}
};
int main()
{
KLinkSolution link;
cout << "请输入链表的长度" << endl;
int nodeNum;
cin >> nodeNum;
cout << "请输入链表节点的值" << endl;
for (int i = 0; i < nodeNum; i++)
{
int temp;
cin >> temp;
link.append(temp); //添加链表的元素
}
cout << "请输入多少个数值为一个反转小组" << endl;
int k;
cin >> k;
int reverseNum = nodeNum / k; //计算出有多少个翻转小组
LinkNode* head = link.getHead()->next; //第一个翻转小组的头节点
for (int i = 0;i < reverseNum; i++) {
head = link.reverseKGroup(head, k);
}
link.print();
}