1025. 反转链表
来源:互联网 发布:网络远程教育可靠吗 编辑:程序博客网 时间:2024/06/05 07:31
一、题目
给定一个常数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
二、个人理解
本题主要考察对数组的反转问题。个人思路为:定义结构体数组,进行逐一的反转。
关键点:
- 如何得到顺序的节点连接。题目中给出的是无序,所以我们要进行转换,一开始我使用两个for循环,但是测试点运行超时,故后来改成用map(数组也可以)进行排序。
- 节点的不断更新。我一开始是从前往后反转,最后的到18分,后来发现这样只有第一轮是正确的,当反转需要很多轮时,上一轮与下一轮经过反转后需进行连接处的更新,故我从后往前反转。
- 无效节点的问题。当我得到24分时,我就知道肯定有个特殊的,果然测试点有开始地址不是头节点的时候,故我们需考虑这一点。
正常版(C++):
#include <iostream>#include <stdio.h>#include <map>using namespace std;typedef struct node { int paddress; int naddress; int data;} linklist;int main(){ map<int, linklist> mp; int first_address, num, k; cin >> first_address >> num >> k; linklist sort_node[num], result[num], node; int addr, data, next; //赋值,并将其插入到map中,key 为地址,值为节点 for (int i = 0; i < num; i++) { cin >> addr >> data >> next; node.paddress = addr; node.data = data; node.naddress = next; mp.insert(pair<int, linklist>(addr, node)); } //遍历,得出节点的顺序连接,注意结束节点的下一地址为-1,且总长度可能不为num int size = 0; while (first_address != -1) { sort_node[size] = mp[first_address]; first_address = sort_node[size].naddress; size++; } //复制 for (int i = 0; i < size; i++) { result[i] = sort_node[i]; } //总共需几轮反转 int total = size / k; //从后往前开始反转(不包括不能反转的) while (total >= 1) { int j = total * k - 1; if (total < size / k) { sort_node[j].naddress = result[j + 1].paddress;//完成一次反转后,进行这次反转的开头地址与即将开始的一轮反转的尾地址更新 } first_address = sort_node[j].paddress;//取出一轮反转的首地址 for (int i = (total - 1) * k; i < k * total; i++) { result[i].paddress = first_address; result[i].data = sort_node[j].data; if (j == (total - 1) * k) { result[i].naddress = sort_node[total * k - 1].naddress;//当进行到反转最后一个时,后地址为原来结点的下地址 break; } result[i].naddress = sort_node[j - 1].paddress; first_address = result[i].naddress;//记录节点的下一地址,为即将反转的节点服务 j--; } total--; } //输出,注意最后一个的输出 for (int i = 0; i < size - 1; i++) { printf("%05d %d %05d\n", result[i].paddress, result[i].data, result[i].naddress); } printf("%05d %d %d\n", result[size - 1].paddress, result[size - 1].data, result[size - 1].naddress);}
关于这一个版本,我只能说我看问题的角度可能过于死板,非要把所有的东西绑在一起,那样太麻烦了。
下一版的主要算法为:对题目分析得出,其实每个节点的后地址就是下一地址的前地址,故我们只需要每个地址的前地址就ok了(而尾部地址一直为-1)。可以将前地址就当作每一节点的地址,然后创建一个数据数组,下标为前地址,值为后地址,另外一个地址数组,存放后地址。然后进行节点的连接,实际为地址的连接,并存放到list数组。直接对地址进行反转(实际就是对节点进行反转),这里就不需要考虑更新问题(因为其中根本没包括后地址)。最后输出时注意后地址就是下一节点的前地址。
超神版(转载):
#include <iostream>#include <algorithm>#include <stdio.h>using namespace std;int main(){ int first, k, n, temp; cin >> first >> n >> k; int data[100005], next[100005], list[100005]; for (int i = 0; i < n; i++) { cin >> temp; cin >> data[temp] >> next[temp]; } int sum = 0;//不一定所有的输入的结点都是有用的,加个计数器 //list对应顺序的节点(以地址表示) while (first != -1) { list[sum++] = first; first = next[first]; } //直接对地址反转,本质上为对节点反转 for (int i = 0; i < (sum - sum % k); i += k) { reverse(list + i * k, list + i * k + k); } //注意输出 for (int i = 0; i < sum - 1; i++) { printf("%05d %d %05d\n", list[i], data[list[i]], list[i + 1]); } printf("%05d %d -1", list[sum - 1], data[list[sum - 1]]); return 0;}
- 1025.反转链表
- 1025.反转链表
- 1025. 反转链表
- 1025. 反转链表
- 1025. 反转链表
- 1025. 反转链表
- 1025. 反转链表
- 1025. 反转链表
- PAT 1025. 反转链表*
- 1025. 反转链表 (25)
- 1025. 反转链表 (25)
- 1025. 反转链表 (25)
- 1025. 反转链表 (25)
- 1025. 反转链表 (25)
- 1025. 反转链表 (25)
- 1025. 反转链表 (25)
- 1025. 反转链表 (25)
- 1025. 反转链表 (25)
- hihoCoder 1419 后缀数组四·重复旋律4(重复次数最多的连续子串)
- 网络流初学整合
- C++程序员学Java系列之十八:继承和抽象
- 八大排序算法
- ac自动机与状态转移
- 1025. 反转链表
- jquery 关于event.target使用的几点说明介绍
- ac自动机与状态转移
- GO语言linux下环境变量
- HDU2577:How to Type 简单DP
- Statement&PreparedStatement&CallableStatement
- Linux系统--/proc/uptime文件中参数说明
- iOS 网络高级编程二:HTTP并没有那么简单
- ajax跨域jsonp的两种解决办法