1097. Deduplication on a Linked List (25)

时间:2022-02-23 19:46:59

题目要求:

Given a singly linked list L with integer keys, you are supposed to remove the nodes with duplicated absolute values of the keys. That is, for each value K, only the first node of which the value or absolute value of its key equals K will be kept. At the mean time, all the removed nodes must be kept in a separate list. For example, given L being 21→-15→-15→-7→15, you must output 21→-15→-7, and the removed list -15→15.

Input Specification:

Each input file contains one test case. For each case, the first line contains the address of the first node, and a positive N (<= 105) which is the total number of nodes. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.

Then N lines follow, each describes a node in the format:

Address Key Next

where Address is the position of the node, Key is an integer of which absolute value is no more than 104, and Next is the position of the next node.

Output Specification:

For each case, output the resulting linked list first, then the removed list. Each node occupies a line, and is printed in the same format as in the input.

Sample Input:
00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854
Sample Output:
00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1

解题思路:

题目要求找出一个线性表中的结点数据绝对值重复的结点,仅保留第一个,其余的按地址连接的顺序去除,并且连接成另一个线性表。

由于题目中的地址是整数,因此不能用传统的链表来存储,而应该借助数组,数组的下标代表地址,而数组内的元素为结点信息,为了方便输出,注意保存结点的自身地址、数据和下一个地址。

难点主要有两个,其一是如何找出所有重复的数,第二是如何连接地址。


难点一的解决方案:

       在输入数据时另外建立一个数组table来保存所有输入数据的绝对值,利用快速排序得到升序序列,在升序序列中找重复,只需要当前元素和相邻元素是否相等,只要有相等即为重复。为了保存多个重复元素和方便以后的查询,建立一个和数据规模一样大的数组,题目要求的K为10的4次方以内,因此建立一个大小为100001的数组dp,所有元素的初值为0,如果发现重复Ki,将数组的Ki位置置为2,之所以置为2,是为了在以后去重复时第一次碰到让2-1=1,只有碰到1才真正删除这个结点,这样就可以避开第一次出现的结点了。

       在后面的处理中,只需要将每个结点的数据绝对值作为索引查询刚才建立的数组dp,如果当前位置为2,则2-1=1(表示第一次碰到重复的元素,置之不理),如果当前位置为1,则删除。


难点二的解决方案:

在线性表中设置前驱结点pre和当前结点p,无重复时的遍历方式和普通线性表一致,即pre的初值为NULL,p的初值为第一个结点,如果没有被删除的元素,则 p后移,pre到达p刚才的位置,如果有要删除的结点,先将pre的next存入p的next,然后p后移,而pre不动(关键点),因为如果有持续被删除的情况,则pre所指向的结点一直在变,直到不再删除,pre和p恢复原来的动作方式。

至于删除元素的存储,只需要另外建立一个线性表,用now指示当前结点,新存入元素后,先更新now的next为新元素的自身地址,然后再把now后移到新插入的元素上,注意在处理结束后让now的next为-1(now此时指向的是最后一个被删除的元素)。


AC代码:

#include <iostream>
#include <math.h>
using namespace std;

#define MAXSIZE	100001
typedef struct node* NodeP;
struct node{

	int myAddress;
	int nextAddress;
	int value;

}nodes[MAXSIZE];
struct deleteNodes{

	deleteNodes * next;
	NodeP data;

};

void printList(int firstAddress){
	int address = firstAddress;
	while (nodes[address].nextAddress != -1){
		printf("%05d %d %05d\n", nodes[address].myAddress, nodes[address].value, nodes[address].nextAddress);
		address = nodes[address].nextAddress;
	}

	printf("%05d %d -1\n", nodes[address].myAddress, nodes[address].value);

}

int compare(const void* a, const void *b){
	return *(int*)a - *(int*)b;
}

int main(){

	int head = 0, N = 0;
	cin >> head >> N;
	int* table = (int*)malloc(sizeof(int)*N);
	int address = 0, value = 0, nextAddress = 0;
	for (int i = 0; i < N; i++){
		scanf("%d%d%d", &address, &value, &nextAddress);
		struct node *p = (nodes + address);
		p->myAddress = address;
		p->nextAddress = nextAddress;
		p->value = value;
		*(table + i) = abs(value);
	}

	int deduplication = -1; 
	qsort(table, N, sizeof(int), compare);

	int deputeTable[10001];

	for (int i = 0; i < 10001; i++){
		deputeTable[i] = 0;
	}

	int lastDepute = -1;

	for (int i = 0; i < N - 1; i++){
		if (table[i] == table[i + 1] && table[i]!=lastDepute){
			deduplication = table[i];
			lastDepute = deduplication;
			*(deputeTable + table[i]) = 2;
		}
	}
	if (deduplication == -1){
		printList(head);
		return 0;
	}

	deleteNodes *deleteList = (deleteNodes*)malloc(sizeof(deleteNodes));
	deleteList->data = NULL;
	deleteList->next = NULL;
	deleteNodes *now = NULL;
	bool fistNum = true;

	node* pre = NULL;
	node* p = nodes + head;

	while (1){

		int* pd = deputeTable + abs(p->value);

		if (*pd > 0){

			if (*pd == 2){
				if (p->nextAddress == -1) break;
				pre = p;
				p = nodes + p->nextAddress;
				*pd = 1;
				continue;
			}

			if (pre != NULL){

				pre->nextAddress = p->nextAddress;

				// 保存被删除的结点
				deleteNodes *n = (deleteNodes*)malloc(sizeof(deleteNodes));
				n->data = p;
				if (now == NULL){
					deleteList->next = n;
					now = deleteList->next;
				}
				else{
					now->data->nextAddress = p->myAddress;
					now->next = n;
					now = now->next;
				}

				// 更新p的值
				if (p->nextAddress == -1) break;
				p = nodes + p->nextAddress;
				continue;

			}

		}// 有重复的情况

		// 没有重复才能来到这里

		// 正常更新p的值
		if (p->nextAddress == -1) break;
		pre = p;
		p = nodes + p->nextAddress;
	}

	printList(head);
	now->data->nextAddress = -1;
	printList(deleteList->next->data->myAddress);

	return 0;
}