PTA天梯 L2-002 链表去重

给定一个带整数键值的链表 L L L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K K K,只有第一个绝对值等于 K K K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如:给定 L L L 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。

输入格式:
输入在第一行给出 L L L 的第一个结点的地址和一个正整数 N ( ≤ 1 0 5 N(≤10^5 N105 ,为结点总数)。一个结点的地址是非负的 5 5 5 位整数,空地址 NULL − 1 −1 1 来表示。
随后 N N 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

可以有多种做法:

  • 可以直接在原始链表上进行操作去重,然后单独提出重复的部分形成新链表
  • 可以存储下来重复部分的地址和不重复部分的地址,输出时按照两部分地址输出
  • 可以开三个链表,一个为初始,一个为去重后的,一个为重复部分,然后填充每个链表

很显然最简单的是第二种做法,并且不容易出错

接下来开始思考怎么实现:

  • 如何存储重复与不重复的地址? 可以开两个vector数组,然后开一个bool类型的标记数组来判断重复与否,判断后直接push_back()进相应的数组。
  • 为什么可以直接压入vector而不用进一步保证他输出时是连接好的链表? 我们在去重的过程中一定是从首节点开始遍历到尾部,首先顺序就一定是正着的,之后在输出的过程中,已经有了所有应该输出的节点,我们并不需要管他们一开始是否相连,只需要在输出的时候输出成连着的链表就可以了,并且键值存的时候是依托于地址值的,并不是存入边上。
  • 如何在输出的时候补齐应有的0? 只需要使用printf()函数中的%05d,意思就是补齐五位,并且不足五位的在数前面补0。

同时需要注意:题目中的两种链表结尾都应该是-1,所以只需要在输出最后输出成-1就行了。

#include<iostream>
#include<vector>
using namespace std;
const int N = 1e5+10;
struct Node {			//用结构体数组模拟链表
	int to;
	int len;
}lst[N];

vector<int>repeatedAddress;		//记录键值重复的地址
vector<int>unrepeatedAddress;	//记录键值不重复的地址
int head;		//首地址
int n;			
bool vis[N];	//标记是否出现过,判断重复

int main() {
	cin >> head >> n;
	for (int i = 0; i < n; i++) {			//读入初始链表
		int address, len, to;
		cin >> address >> len >> to;

		lst[address].to = to;
		lst[address].len = len;
	}

	//从首地址开始遍历整个链表,如果当前键值没有出现过,就标记上并且把地址值压入记录数组
	//如果出现过,那就吧地址压入记录重复地址的数组
	for (int i = head; i != -1; i = lst[i].to) {
		int t = lst[i].len;	//取出键值

		if (vis[abs(t)]) {	
			repeatedAddress.push_back(i);
		}
		else {
			vis[abs(t)] = 1;
			unrepeatedAddress.push_back(i);
		}
	}

	auto& unrep = unrepeatedAddress;	//引用
	int len = unrep.size();				//数组长度
	for (int i = 0; i < len; i++) {		//遍历
										//补0对齐输出
		printf("%05d %d ",unrep[i],lst[unrep[i]].len);

		if (i == len - 1)printf("-1\n");	//依照题目链表的尾部为-1,那么就在输出最后一个数的时候输出-1
		else printf("%05d\n",unrep[i+1]);	
	}


	auto& rep = repeatedAddress;
	len = rep.size();
	for (int i = 0; i < len; i++) {
		printf("%05d %d ",rep[i],lst[rep[i]].len);

		if (i == len - 1) printf("-1\n");
		else printf("%05d\n",rep[i+1]);
	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值