版权声明:转载请注明出处 https://blog.csdn.net/qq799028706/article/details/88840953
1. 题目
给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。
输入格式:
输入在第一行给出 L 的第一个结点的地址和一个正整数 N(≤105
,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 -1 来表示。
随后 N 行,每行按以下格式描述一个结点:
地址 键值 下一个结点
其中地址是该结点的地址,键值是绝对值不超过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
2. 思路
第一个关键点是怎么模拟链表的行为,得想办法将链表连接在一起
关键的一句话是下面这句话
一个结点的地址是非负的 5 位整数,空地址 NULL 用 -1 来表示。
因此,我们可以用下标表示当前结点地址,结点的data成员表示数据域,结点里的next成员表示下一个结点
然后得到我们的结构
struct node {
int data;
int next;
};
node list[100005];
第二个关键点是去重。
这一步的思路是使用一个数组去重,使用两个数组分别记录两个链表
int vis[100005]; // 去重
int l1[100005], l2[100005]; // 记录两个链表地址
3. 实现
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
struct node {
int data;
int next;
};
int vis[100005]; // 去重
int l1[100005], l2[100005]; // 记录两个链表地址
node list[100005];
int main() {
int head, n;
scanf("%d%d", &head, &n);
for (int i = 0; i < n; i++) {
int t;
scanf("%d", &t);
scanf("%d%d", &list[t].data, &list[t].next);
}
int p1 = 0, p2 = 0;
for (int i = head; i != -1; i = list[i].next) {
int t = abs(list[i].data);
if (vis[t] == 0) {
vis[t] = 1;
l1[p1++] = i;
} else {
l2[p2++] = i;
}
}
for (int i = 0; i < p1; i++) {
int pos = l1[i];
if (i + 1 == p1) {
printf("%05d %d -1\n", pos, list[pos].data);
} else {
printf("%05d %d %05d\n", pos, list[pos].data, l1[i+1]);
}
}
for (int i = 0; i < p2; i++) {
int pos = l2[i];
if (i + 1 == p2) {
printf("%05d %d -1\n", pos, list[pos].data);
} else {
printf("%05d %d %05d\n", pos, list[pos].data, l2[i+1]);
}
}
return 0;
}
很好的题目,故此记录