有重复元素的数组的一个很重要的思路

昨天在做17年东华复试上机的题目,遇到了这样一个问题:

(4)
有n(n很大)个范围为0~32767数字,其中有大量重复的数,在main函数中已读入到data数组中,请编写函数fun,计算剔除重复数字之后,还剩下几个数。
fun函数的功能是:传入两个形参,一个是数组data,一个是n的值,经过计算,返回剔除重复数字后剩下的数字的个数。 比如,程序运行时输入:
5 1 1 3 1 3 则程序输出:2
要求:请衡量时间复杂度和空间复杂度,尽量设计高效算法。请在prog1.c最前面的注释部分介绍自己的算法。
注意:部分源程序存在文件prog1.c中。 请勿改动主函数main和其他函数中的任何内容,仅在函数fun的花括号中填入你编写的若干语句。

开始我的想法是这样的:
先对数组排个序。初始计数为1,因为至少一个数组至少有一个不一样的数。再遍历有序数组,如果当前元素与后一个元素不等,那么计数加1,否则不变。代码如下:

int flag = 0; 
	int i, j, temp, count = 1;
	
	for (i = n - 1; i >= 1; i--) {// 给数组排序
		flag = 0;
		for (j = 0; j < i; j++) {
			if (array[j] > array[j + 1]) {
				flag = 1;
				temp = array[j];
				array[j] = array[j + 1];
				array[j + 1] = temp;
			}
		}
		if (flag == 0) {
			break;
		}
	}
	printf("排序后:\n");
	for (i = 0; i < n; i++)
		printf("%d ", array[i]);
	printf("\n");
	
	for (i = 0; i < n - 1; i++) {// 计数
		if (array[i] != array[i + 1]) {
			count++;
		}
	}

这种方式虽然说解决了问题,但时间复杂度有点高【O(n2)】,我想了很久找不到解决的办法,于是就去看了看学长的代码。从学长那里我学到一个很好的思路:

准备一个标记数组flag,数组下标代表题干数组中的数,标记数组元素的值非零就代表题干数组中出现了非零值的下标数,比如,flag[20] =
3代表题干数组中有三个数为20,flag[21] = 0代表题干数组中没有出现21。这样一来只需要统计flag数组中的非零元素即可

代码如下:

int flag[32768] = {0};
	int i, count = 0;
	
	for (i = 0; i < n; i++) {
		flag[array[i]]++;
	}

	for (i = 0; i < 32768; i++) {
		if (flag[i] != 0) {
			count++;
		}
	}

不仅代码简练了许多,时间复杂度也降为了O(n) ,和这个代码一比,我的就显得low爆了。
参考:https://blog.csdn.net/wy_97/article/details/88616151

你可能感兴趣的:(东华复试上机准备,算法)