传送门
https://pintia.cn/problem-sets/994805260223102976/problems/994805296180871168
题目
给定一个常数K以及一个单链表L,请编写程序将L中每K个结点反转。例如:给定L为1→2→3→4→5→6,K为3,则输出应该为3→2→1→6→5→4;如果K为4,则输出应该为4→3→2→1→5→6,即最后不到K个元素不反转。
输入格式:
每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址、结点总个数正整数N(<= 105)、以及正整数K(<=N),即要求反转的子链结点的个数。结点的地址是5位非负整数,NULL地址用-1表示。
接下来有N行,每行格式为:
Address Data Next
其中Address是结点地址,Data是该结点保存的整数数据,Next是下一结点的地址。
输出格式:
对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。
输入样例:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
输出样例:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1
分析
主要是用数组来模拟链表的实现:
方法1(有一测试点超时):首先先将数据存入三个数组中(address数组,data数组,next数组),然后按照地址首尾相接,有序放进第四个数组中,然后对第四个数组元素按照每k个数一反转,接着,从头遍历数组,将next的地址替换掉,然后按照第四个数组的顺序,分别输出地址、数值和下一地址。
思考:应该是在地址首尾相接并有序存放进第四个数组这一过程中效率太低,但是由于数据是随机输入的,也没有办法优化查找方法,只能根据遍历来查找,所以才会超时;第二处是将next地址替换掉根本就是多此一举,因为上一个元素的next就是下一个元素的address,所以这里也浪费时间遍历了一遍。综合考虑下,舍弃此方法。
方法2(参照别人的做法):大体做法与方法1类似,但是优化了查找地址的方法。
首先因为地址是五位数,所以在开始就新建个大小为100000的数组,在第一遍存数据的时候,就根据地址作为下标存入这个数组中,一切输入都存储完毕后。根据初始地址,一个一个在地址数组中查找对应的值,并将其存入结构体数组中(结构体有三个变量:address,data,next),最后使用STL中的reverse方法翻转,然后并输出结构体数组中的结果即可。具体方法见源代码。
此次解题过程中用到了新的东西:pair类型,下面来简要介绍一下。
概念:pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同,基本的定义如下:
pair a;
表示a中有两个类型,第一个元素是int型的,第二个元素是string类型的,如果创建pair的时候没有对其进行初始化,则调用默认构造函数对其初始化。
pair a("James", "Joy");
也可以像上面一样在定义的时候直接对其初始化。
由于pair类型的使用比较繁琐,因为如果要定义多个形同的pair类型的时候,可以时候typedef简化声明:
typedef pair author;
author pro("May", "Lily");
author joye("James", "Joyce");
而如何对pair对象进行操作呢?
1.对于pair类,由于它只有两个元素,分别名为first和second,因此直接使用普通的点操作符即可访问其成员
typedef pair author;
author pro;
pro.first = "Lily";
pro.second = "Poly";
等同于
pair author("Lily", "Poly");
2.生成新的pair对象
可以使用make_pair对已存在的两个数据构造一个新的pair类型:
int a = 8;
string m = "James";
pair newone;
newone = make_pair(a, m);
这里我对pair的理解就是类似结构体一样的东西,然后提供了first和second作为访问其中变量的方法。
源代码
//C/C++实现
#include
#include
#include
using namespace std;
typedef pair P;
P addr[100000];
struct node{
int address, data, next;
};
int main(){
int start, n, k, address, data, next;
scanf("%d %d %d", &start, &n, &k);
vector list;
for(int i = 0; i < n; ++i){
scanf("%d %d %d", &address, &data, &next);
P p;
p.first = data;
p.second = next;
addr[address] = p;
}
int tmp = start;
while(tmp != -1){
node n;
n.address = tmp;
n.data = addr[tmp].first;
n.next = addr[tmp].second;
list.push_back(n);
tmp = n.next;
}
for(int l = 0, index = 0; l < list.size() / k; ++l){
reverse(list.begin() + index, list.begin() + index + k);
index += k;
}
int o = 0;
for(; o < list.size() - 1; ++o){
printf("%05d %d %05d\n", list[o].address, list[o].data, list[o + 1].address);
}
printf("%05d %d -1\n", list[o].address, list[o].data);
return 0;
}