PAT (Basic Level) Practice 1025 反转链表题解思路
这题是把n个结点的链表,每k个数反转,而且最后不足k个数不反转。
比如给定L为1→2→3→4→5→6,K为3,则输出应该为3→2→1→6→5→4;如果K为4,则输出应该为4→3→2→1→5→6
然后这里的链表给出结点地址,数据,及下一节点的地址,格式如下
00000 4 99999
一开始没思路,自己写了个很烂的代码,只能通过一个case。后来搜索解题思路,大致是用一个数组存入所有结点,然后按起始地址,顺序重排所有结点,最后每k个结点反转。
用一个结构体来定义结点
typedef struct
{
int addr;
int data;
int next;
}List,*pList;
数组用new申请一个堆空间,因为题目结点上限是10w个
pList pl = new List[100000]();
数据输入部分用scanf提高时间效率
然后按每个节点的起始地址存入到数组中,好处是可以利用数组O(1)的复杂度,瞬间访问到某个结点,而不用遍历整个数组
List t; for ( i=0 ; i < n ; ++ i ) { scanf("%d%d%d",&t.addr,&t.data,&t.next); pl[t.addr]=t; }
按链表起始结点,让所有结点有序,直到最后一个结点,这里用了STL的Vector数据结构存储有序的链表
vector<List> v; while(beg!=-1) { v.push_back(pl[beg]); beg=pl[beg].next;//更新为下一节点的起始地址 }
翻转链表,就是把k个结点入栈,再出栈存到新的向量中;如果剩余不足k个数,则顺序存入向量中
记得还要修正next地址,就是让翻转后的链表结点next地址正确。这一步不必在翻转的代码中做,只要在最后打印输出的时候,把next地址修改为下一节点的起始地址
完整代码如下
#include <iostream>
#include <vector>
#include <stack>
#include <stdio.h>
using namespace std;
typedef struct
{
int addr;
int data;
int next;
}List,*pList;
int main()
{
vector<List> v,v2;
pList pl = new List[100000]();//用一个数组存储数据
List t;
int beg;
int n,k,i;
cin >> beg >> n >> k;
for ( i=0 ; i < n ; ++ i )
{
//cin >> pl[i].addr >> pl[i].data >> pl[i].next ;
scanf("%d%d%d",&t.addr,&t.data,&t.next);
pl[t.addr]=t;//让每个节点的起始地址直接作为数组的下标
}
if(beg == -1) //首地址为-1.直接输出
{
printf("-1\n");
return 0;
}
//用一个vector按开始地址顺序存储链表,否则用暴力法双重循环查找链表的起始地址超时
while(beg!=-1)
{
v.push_back(pl[beg]);
beg=pl[beg].next;//更新为下一节点的起始地址
}
//每k个一组,将向量数据入栈,再出栈,存入新的向量
//auto it = v.begin();
vector<List>::iterator it=v.begin();
for ( ; it != v.end() ; )
{
stack<List> s;
if(v2.size()+k <= v.size())//要有k个数才逆转链表
{
for (i=0;i<k;++i)
{
s.push(*it);
++it;
}
while(!s.empty())
{
List temp = s.top();
s.pop();
v2.push_back(temp);
}
}else{
v2.push_back(*it);//小于k个数,不逆转,直接存入向量
++it;
}
}
//输出
it = v2.begin();
for ( ; it != v2.end()-1 ; ++it)
{
it->next=(it+1)->addr;//修正逆转后的链表的next地址
printf("%05d %d %05d\n" , it->addr ,it->data ,it->next);
}
it->next=-1;
printf("%05d %d %d\n" , it->addr ,it->data ,it->next);
return 0;
}

浙公网安备 33010602011771号