天梯赛 L2-002 链表去重 (25 分)
题目
给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。
输入格式
输入在第一行给出 L 的第一个结点的地址和一个正整数
N
N
N(≤
1
0
5
10^5
105,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 −1 来表示。
随后 N 行,每行按以下格式描述一个结点:
地址 键值 下一个结点
其中地址
是该结点的地址,键值
是绝对值不超过
1
0
4
10^4
104的整数,下一个结点是下个结点的地址。
输出格式:
首先输出去重后的链表,然后输出被删除的链表。每个结点占一行,按输入的格式输出。
测试样例
输入样例:
00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854
输出样例:
00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1
简单分析:
还是属于模拟题的范围吧,但是,哎,感觉好难。
代码
1 结构体模拟链表,最后排序再输出(不推荐使用)。
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int N = 1e5 + 5;
struct Node {
int head, num, next;
int order;
bool operator< (const Node& n) const {
return order < n.order;
}
}list[N];
int start, n;
set<int> se;
int main() {
cin >> start >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
list[x].head = x;
cin >> list[x].num >> list[x].next;
}
int x1 = 0, x2 = 0;
for (int i = 0; i < N; i++)
list[i].order = 2 * N;
for (int i = start; i != -1; i = list[i].next) {
if (!se.count(abs(list[i].num))) {
se.insert(abs(list[i].num));
list[i].order = x1++;
}
else list[i].order = N + x2++;
}
sort(list, list + N);
int x = x1 + x2;
for (int i = 0; i < x; i++)
if (i != x1 - 1 && i != x - 1)
printf("%05d %d %05d\n", list[i].head, list[i].num, list[i + 1].head);
else
printf("%05d %d -1\n", list[i].head, list[i].num);
return 0;
}
2 推荐,数组模拟单链表
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const int N = 1e5 + 5;
int n;
int head, e[N], ne[N]; // 数组模拟单链表,可以直接读取下标元素
bool st[N];
vector<int> a, b;
int main() {
// 数据读入
cin >> head >> n;
while (n--) {
int add, num, next;
cin >> add >> num >> next;
e[add] = num, ne[add] = next;
}
// 依题意,将链表拆分为两个,只用记录头节点位置即可,因为数组可以直接访问下标
for (int i = head; ~i; i = ne[i])
if (!st[abs(e[i])]) {
st[abs(e[i])] = true;
a.push_back(i);
}
else b.push_back(i);
// 输出部分
for (int i = 0; i < a.size(); i++) {
if (i == a.size() - 1) {
printf("%05d %d -1\n", a[i], e[a[i]]);
break;
}
printf("%05d %d %05d\n", a[i], e[a[i]], a[i + 1]);
}
for (int i = 0; i < b.size(); i++) {
if (i == b.size() - 1) {
printf("%05d %d -1\n", b[i], e[b[i]]);
break;
}
printf("%05d %d %05d\n", b[i], e[b[i]], b[i + 1]);
}
return 0;
}
感悟与收获
为什么自己这么菜,哭哭。