C语言-- NOI/1.10 09明明的随机数

文章讲述了如何使用C语言中的冒泡排序和数组特性,高效地对1到1000之间的随机数进行去重和排序的操作。作者分享了一种巧妙的方法,通过判断数组元素是否已填充,实现在输入阶段即完成去重,并在输出时自然排序。
摘要由CSDN通过智能技术生成

题目如下

总时间限制: 1000ms

内存限制:  65536kB

描述

明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。 然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。 请你协助明明完成“去重”与“排序”的工作。

输入

有2行,第1行为1个正整数,表示所生成的随机数的个数:N;
第2行有N个用空格隔开的正整数,为所产生的随机数。

输出

也是2行,第1行为1个正整数M,表示不相同的随机数的个数。 第2行为M个用空格隔开的正整数,为从小到大排好序的不相同的随机数。

样例输入

10
20 40 32 67 40 20 89 300 400 15

样例输出

8
15 20 32 40 67 89 300 400

我的思路:

排序-->去重-->计数并输出

(这是一个常规思路,容易想到。 就是根据题目要求,实现每一个小环节)

int main()
{
	int a[100];
	int n, i, j,t,cnt=0;
	//输入
	scanf("%d",&n);
	for (i = 0;i < n; i++){
		scanf("%d", a + i);
	}
	//将所有随机数排序 这里采用的是冒泡排序
	for (i = 0;i < n; i++) {
		for (j = 0;j < n - i - 1;j++) {
			if (a[j] > a[j + 1]) {
				t = a[j];
				a[j] = a[j + 1];
				a[j + 1] = t;
			}
		}
	}
	//计算去重后随机数的个数为cnt
	for (i = 0;i < n;i++) {
		if (a[i] == a[i + 1]) {}
		else cnt++;
	}
	printf("%d\n", cnt);//输出去重后随机数的个数
    //去重输出随机数
	for (i = 0;i < n;i++) {
		if (a[i] == a[i + 1])//如果有相同的数,就用continue跳过输出,使相同的随机数只被输出一次
			continue;
		else printf("%d ", a[i]);
	}
	return 0;
}

这里,因为题目要求只需要输出去重的数字就行了,所以就简单地用了一个if-else语句加continue,使每个数只被输出一次。

for (i = 0;i < n;i++) {
		if (a[i] == a[i + 1])
			continue;
		else printf("%d ", a[i]);
	}

如果是要删除一个数组中重复的数字,就需要用几个循环先判断有没有重复的数,若有重复数字,就要依次将数组大小减一,也就是删掉重复元素(和覆盖的意思差不多)

网上的解法:

  int main(){
      int N,a[1001]={0},t,i;
      int count=0; 
     scanf("%d",&N);
      for(i=0;i<N;i++){
         scanf("%d",&t);
          if(a[t]==0){
              a[t]=t;
             count++;
        }
     }
     printf("%d\n",count);
     for(i=0;i<1001;i++){
         if(a[i]!=0)
             printf("%d ",a[i]);
     }
     return 0;
 }

第一眼:好简洁啊!

再看:太妙了吧!

下面说说自己的理解吧(自己理一遍),如果对你也有帮助就更好啦!(O(∩_∩)O)

首先,和普通解法不一样的是这个数组a, 作者将数组a的大小初始化为1001,同时将每个元素赋值为0。

这是有用处的,妙也就是在这里。

题目不是说,生成的随机数大小在1到1000嘛,显然,设置1001大小的数组a是为了后续将数组元素下标与随机数的值联系起来。

看!接下来的随机数输入部分。

 int N,a[1001]={0},t,i;

a[t]=t;  就是将一个随机数 t 填入了数组a中下标为t的位置。

前面的 if(a[t]==0) 是用来判断这个下标为t的位置有没有被 “填入”过,如果被 “填入”过,就不会被二次“填入”。

-----这样,有了if判断就在输入的时候同时解决了去重的环节 !!

count++; 计数。

 for(i=0;i<N;i++){
         scanf("%d",&t);
          if(a[t]==0){
              a[t]=t;
             count++;
        }
     }

 

然后,遍历数组a输出被填入的随机数

因为输入时是 数组下标=随机数的值,所以遍历输出不为0的a数组元素就自然是按从小到大的顺序输出的了!

-----这样,就在输出的时候解决了排序的环节!!

for(i=0;i<1001;i++){
         if(a[i]!=0)
             printf("%d ",a[i]);
     }

总结一下

这个解法很巧妙地利用了数组的特点。

这给我们的启示是:有时候,合理利用数组的特点可以简化很多步骤。

在以后可以多去尝试探索、思考这样的优化解法。

由此想到的另一个利用数组特点优化解法的例子是  “统计每个数字出现的数字”

建立一个数组a

出现1,则a[1]++;

出现7,则a[7]++;

……

这样就用a[1]、a[7]来计数1和7出现的次数,就省去了一些繁复的变量定义,而且清晰直观。

以上只是自己在学c过程中的记录,希望也能帮到你。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值