解题思路详解
🌟 题目分析
本题要求对单链表进行分段反转,需注意以下要点:
- 剩余不足K个的结点不反转
- 结点地址是5位非负整数(需处理补零输出)
- 可能存在无效结点(输入中的N不一定是实际链表长度)
🛠️ 实现策略分解
1. 数据存储结构
- 数组模拟内存:使用
Node Nodes[100000]
,直接用地址作为下标访问结点 - 结点结构:包含
data
(数据)和next
(下个结点地址) - 优势:相比动态链表,数组访问时间复杂度为O(1)
2. 链表有效性处理
- 计算实际长度:遍历链表直到遇到-1,统计有效结点数
Size
- 意义:避免处理无效结点,且确定可反转的完整段数
Size/K
3. 分段反转核心逻辑
for(int i = K; i <= Size; i += K)
- 段头定位:
tempBeginAr
标记当前段起始地址 - 段尾定位:通过K次
next
遍历找到段尾endAr
- 段内反转:将当前段的指针方向逐个反转
- 段间连接:通过
lastEnd
记录前一段尾结点,实现段间衔接
4. 指针调整细节
- 首段特殊处理:更新全局起始地址
beginAr
- 后续段处理:将前一段尾结点的
next
指向当前段头 - 段尾记录更新:
lastEnd
始终指向已处理段的最后一个结点
5. 输出格式化处理
- display函数:处理地址补零和-1的特殊输出
- 顺序遍历输出:按照处理后的链表顺序输出每个结点信息
🎯 复杂度分析
- 时间复杂度:O(N)
每个结点被遍历不超过3次(计算长度、反转处理、输出) - 空间复杂度:O(1)
除存储结点的固定数组外,仅使用有限变量
关键技巧总结
- 数组模拟法:用空间换时间,实现快速地址访问
- 三段式处理:定位段尾 → 反转段内指针 → 连接前后段
- 边界处理:通过
Size/K
控制完整段数,避免处理残余段 - 地址格式化:使用多级条件判断实现5位补零输出
具体代码如下:
#include<iostream>
using namespace std;
// 链表结点类定义
class Node{
public:
int data; // 结点存储的数值
int next; // 下个结点的地址(模拟指针)
Node(); // 构造函数初始化
};
// 格式化输出地址函数(保证5位补零)
void display(int num){
if(num < 0){
cout<<num;
return;
}
// 通过多级补零保证输出5位地址
if(num < 10000) cout<<"0";
if(num < 1000) cout<<"0";
if(num < 100) cout<<"0";
if(num < 10) cout<<"0";
cout<<num;
}
Node::Node(){
// 初始化结点数据成员
data = 0;
next = 0;
}
int main(){
Node Nodes[100000]; // 用数组模拟内存空间(地址直接作为下标)
int beginAr, N, K; // 链表起始地址、结点总数、反转步长
cin>>beginAr>>N>>K;
// 读取所有结点数据存入数组
int t = N;
while(t--){
int Address, Data, Next;
cin>>Address>>Data>>Next;
Nodes[Address].data = Data;
Nodes[Address].next = Next;
}
int tempBeginAr = beginAr; // 当前处理段的起始地址
int lastEnd = -1; // 上一段的尾结点地址
int Size = 0; // 计算有效链表长度(可能有无效结点)
// 遍历链表计算实际长度
int temp = beginAr;
while(temp != -1){
Size++;
temp = Nodes[temp].next;
}
// 分段处理反转逻辑
for(int i = K; i <= Size; i += K){ // 每K个为一组处理
int endAr = tempBeginAr; // 当前段的尾结点地址
// 定位当前段的尾结点
for(int j = 1; j < K; ++j){
endAr = Nodes[endAr].next;
}
int tempBe = Nodes[endAr].next; // 保存下一段的起始地址
int t = tempBeginAr; // 保存当前段原始起始地址(反转后将变为段尾)
// 反转当前段内的指针方向
for(int j = 1; j < K; ++j){
int tempAr = Nodes[tempBeginAr].next;
Nodes[tempBeginAr].next = Nodes[endAr].next;
Nodes[endAr].next = tempBeginAr;
tempBeginAr = tempAr;
}
// 处理段间连接
if(i == K){ // 第一段特殊处理:更新全局起始地址
lastEnd = beginAr; // 原起始地址变为第一段尾
beginAr = endAr; // 全局起始地址更新为当前段头
} else { // 后续段连接前一段
Nodes[lastEnd].next = endAr; // 前一段尾连接当前段头
lastEnd = t; // 更新段尾记录
}
tempBeginAr = tempBe; // 移动到下一段起始地址
}
// 遍历输出结果链表
int Address = beginAr;
while(Address != -1){
display(Address);
cout<<" "<<Nodes[Address].data<<" ";
display(Nodes[Address].next);
cout<<endl;
Address = Nodes[Address].next;
}
}