练习作业4: 和8有关的数字 , 不当老大 , 幂字符串

这篇博客介绍了三道C语言练习题:涉及8的关联数字判断、不当老大的年龄差计算以及幂字符串的最大n值。通过详细分析题目和解题思路,帮助读者理解和解决问题,提高C语言编程能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

练习作业4: 和8有关的数字 , 不当老大 , 幂字符串



前排提示,本次作业的基础讲解很细致,弄清楚这个卡口会对C语言学习有极大帮助!


问题 A: 和8有关的数字

序号:1099

题目描述

把1到n之间(包含n),符合以下条件之一的数字,依次打印出来。

①含有数字8

②各个数位上的数字和是8

③是8的倍数

输入

整数n,n>1

输出

符合条件的所有整数清单,一行

样例输入
30
样例输出
8 16 17 18 24 26 28
思路过程:

​ 本题考验函数的使用和输出格式要求。首先读题,要求输入n(n>1),输出满足三个条件任意一条的数字,这里第二条注意是各个位,不是个位

​ 我们看输出,每两个数之间有空格,头尾都没有,这就意味着我们不能使用%d(空格)或者 (空格)%d一路输出到底,先选第一种,输出%d(空格),那么,当输出最后一个数时,我们只输出%d即可,问题变成了如何确定输出的最后一个数?我们知道,我们输入的n是控制结束的,我们无法知道最后一个符合条件的数是多少,所以这条路不行!我们换第二条,输出(空格)%d,只有第一个数是仅%d,所以,问题又变成了怎样判断输出的是第一个数,这个简单,设置一个flag,flag为初值,即为第一个数,往后flag变化,输出(空格)%d就好啦。

void put(int i,int flag)//flag的变化在主函数中体现
{
    if(flag==0)
        printf("%d",i);
    else printf(" %d",i);
}

​ 本题有一个,算是漏洞的地方,因为8一定是第一个输出的数,所以输出加一条if(i==8) printf("%d");然后后面输出就是printf(" %d");了,这样确实判断机给过的,但是希望同学能真正懂这块输出该怎么判断与如何掌握输出规则。

​ 接下来是函数问题,为了增加函数的可读性,我们需要将函数拆分,有三个判断函数,我们就定义三个函数,加上主函数和输出函数共五个。三个判断函数不是很难,主要是主函数的调用,这里我们写一个判断语句,既然是三个条件之一满足,那我们不妨让每个判断函数都返回一个值,再用if判断,这里精髓的判断条件用或语句(||)完成,如果其一成立,即可调用输出函数。

if(judgement1(i)||judgement2(i)||judgement3(i))//三个函数都返回0或1,成立其一即可输出
        	put(i,flag++);//这里体现了flag的变化!

​ 这样,本题的难点就解决了。

附:

​ 由于有部分同学不理解函数形式,对于这三个函数,我们稍微来回顾一下吧

第一个:判断数字为8倍数

最简单的

	if(i%8==0)	return 1;
	else return 0;

第二个:判断数字中含有数字8

​ 首先有定义int i=*判定数* , p,我们采用标准最简的方法,逐个对i的最后一位进行判断,放入while循环,先不看循环条件,我们看循环体,取出i的最后一位放到p中,判断p是不是8,是就表明是8,不是就不是(那当然233),如果不是那就i去掉最后一位,由于整数的整除性,我们只要让i/10即可,然后判断条件就是i不为0就继续。如果i被除到0了还没有符合条件的,那就是i不符合了。

	while(i!=0)
    {
    	p=i%10;
    	if(p==8)	return 1;//表示是
    	i/=10;
    }
    return 0;//表示不是

第三个:判断数字各个位和为8

​ 首先有定义int i=*判定数*,s=0,还是用类似上面的方法,逐个取i的最后一位,由于要判断数字各个位和是否为8,我们就要把各个数字相加存到s里

	
	while(i!=0)//直到i被除尽
	{
		s+=i%10;//取i最后一位加到s里,s有初值0
		i/=10;
	}
	if(s==8)	return 1;//判断是
	else	return 0;//判断否

最后再次提醒!函数是灵活的!不要一条主函数写到底,不管是函数的可读性还是结构性都会大受打击!而且以后工作中这样的代码不利于维护,更会体现出个人的水平的高低。

Example Answer:
#include<stdio.h>
void put(int i,int flag)//输出函数
{
    if(flag==0)//判断flag,即是否为第一个输出数
        printf("%d",i);//由于flag初值为0,即如果flag为0就是第一个数
    else printf(" %d",i);
}

int judgement1(int i)//判断是否各个位上含有8
{
	int p;
	while(i!=0)
    {
    	p=i%10;
    	if(p==8)	return 1;
    	i/=10;
    }
    return 0;
} 

int judgement2(int i)//判断是否各位和为8
{
	int s=0;
	while(i!=0)
	{
		s+=i%10;
		i/=10;
	}
	if(s==8)	return 1;
	else	return 0;
}

int judgement3(int i)//判断是否为8倍数
{
	if(i%8==0)	return 1;
	else return 0;
}

int main()
{
    int i,n,flag=0;//flag初值为0
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        if(judgement1(i)||judgement2(i)||judgement3(i))//精髓的 或 语句
        	put(i,flag++);
    }
    return 0;
}

问题 B: 不当老大

序号:1056

题目描述

“当老大有什么意思!”小明如是想。于是他把班级里的同学按年龄排序,最为推崇第二大的同学了!然而,他也很推崇倒数第二大的同学。请问这两个同学相差多少岁?

输入

第一行是数据的组数 nCase (n<=5),每组测试数据的第一行是一个整数 n(n>=2) ,表示班级里有 n 位同学。以下是 n 位同学的年龄。

输出

年龄第二和倒数第二的同学的年龄差。

样例输入
2
50
16 19 4 25 20 5 28 28 30 26 13 18 2 14 1 30 14 2 3 17 6 6 24 16 16 30 2 29 16 27 9 29 24 7 14 5 7 6 13 1 21 1 18 8 5 6 2 7 14 7
20
9 29 24 7 14 5 7 6 13 1 21 1 18 8 5 6 2 7 14 7
样例输出
29
23
提示

年龄差不能是负数

思路过程:

​ 本题与第一期“笨鸟先飞”相同点,先输入有几组数据,然后输入第一组的数据的个数,再输入第一组数据,接着输入第二组数据的个数,再输入第二组数据,重复直到第n组。

​ 不当老大的要求,就是不当最大最小的那个数,那么最大最小的那个数要不要找出来?答案是要的,那么找出来是取这个数,还是取它的下标,本题有多种解法,我们继续分析。

​ 我们先输入Case,然后输入数据个数n,这里直接定义数组a[n],然后用for循环赋值输入数据了。

scanf("%d",&Case);
while(Case--)
{
	scanf("%d",&n);
	int a[n];
	for(i=0;i<n;i++)
		scanf("%d",&a[i]);
    ...未完

接着,我们写cal函数来进行计算,传递参数为数据个数数组a,我们先遍历数组,找出最小最大值。取出了下标(***后皆为下标!***)。

for(i=0;i<n;i++)
	if(a[max1]<a[i])
		max1=i;
for(i=0;i<n;i++)
	if(a[min1]>a[i])	
		min1=i;

接着给第二大第二小的变量赋值,这里我把最大数赋给了第二小的数,把最小数赋给了第二大的数,一定要注意赋值考虑会不会对接下来的计算有影响。我的想法是因为这样交叉赋值,还赋了最值,比如说第二大的初值我赋了最小值,接下来的判断中总会有值能覆盖掉它的。

max2=min1;
min2=max1;

然后如果值小于最大值且大于其他任何值,那就把它下标给第二大数,第二小数亦然。注意,如果下标和最大值最小值相同要continue,因为如果最大值和第二大值都相同,这里判断会出错。第二大第二小值可以和最大值最小值相等,如果存在的话!(吐槽出题人,这叫老二嘛= =)

注意看if(a[max2]<a[i]&&a[i]<=a[max1]) max2=i;第二大值比当前数小,且当前数小于等于(<=)最大值,那这个数就要取代原第二大值,这里就给了下标。第二小值同理。

贴上代码帮助理解

	for(i=0;i<n-1;i++)
	{	if(i==max1)	continue;
		if(a[max2]<a[i]&&a[i]<=a[max1])	max2=i;
	}
		
	for(i=0;i<n-1;i++)
	{
		if(i==min1)	continue;
		if(a[min2]>a[i]&&a[i]>=a[min1])	min2=i;
	}

最后返回两值相减,提示中告诉我们

年龄差不能是负数

所以记得加上绝对值abs和头文件math.c。其实第二大减第二小就是正数…
测试的时候发现问题,一定要加绝对值abs!否则不给过。

问题就解决啦。

以上是原数列直接找值的方法,本题还有另一种思路,也比我先想的这种好实现一点,那就是排序

前部分代码相同,后面我们可以对数列进行排序

	int i,j,t;
	for(i=0;i<n-1;i++)
		for(j=0;j<n-1-i;j++)
			if(a[j]>=a[j+1])
			{
				t=a[j];
				a[j]=a[j+1];
				a[j+1]=t;
			}

有同学不清楚排序,这里展开讲一下:

这是冒泡法排序,i=0第一次大循环,j进行第一次小循环,如果一个数比它后面的数大,就把它和后面的数交换。这样第一次小循环走完最后一个数一定是最大的数!然后第二次大循环开始,第二次小循环做到n-1-i,也就是说做到了上一次循环的前一位,而上一次循环会把这次循环最大的值放最后,如此一来,大循环结束时,数列排序已经完成了。

这样a[1]就是第二小,a[n-1]就是第二大的数了。

直接在原数列找值,排序找值,都是很好的方法!

Example Answer 1:
#include<stdio.h>
#include<math.h>
int cal(int n,int a[])
{
	int i,max1=0,max2,min1=0,min2,t;
	for(i=0;i<n;i++)
		if(a[max1]<a[i])
			max1=i;
	for(i=0;i<n;i++)
		if(a[min1]>a[i])	
			min1=i;//找出最大最小值下标
	max2=min1;
	min2=max1;//赋初值
	for(i=0;i<n-1;i++)
	{	if(i==max1)	continue;//注意continue
		if(a[max2]<a[i]&&a[i]<=a[max1])	max2=i;
	}
		
	for(i=0;i<n-1;i++)
	{
		if(i==min1)	continue;
		if(a[min2]>a[i]&&a[i]>=a[min1])	min2=i;
	}
	return abs(a[max2]-a[min2]);//绝对值
}

int main()
{
	int n,Case,i;
	scanf("%d",&Case);
	while(Case--)//用自减
	{
		scanf("%d",&n);
		int a[n];
		for(i=0;i<n;i++)
			scanf("%d",&a[i]);
		printf("%d\n",cal(n,a));//输出调用函数cal
	}
	return 0;
}
Example Answer 2:
#include<stdio.h>
#include<math.h>
void cal(int n,int *a)//这里用到了指针!
{
	int i,j,t;
	for(i=0;i<n-1;i++)//排序处理
		for(j=0;j<n-1-i;j++)
			if(a[j]>=a[j+1])
			{
				t=a[j];
				a[j]=a[j+1];
				a[j+1]=t;
			}
}
int main()
{
	int n,Case,i;
	scanf("%d",&Case);
	while(Case--)//用自减
	{
		scanf("%d",&n);
		int a[n];
		for(i=0;i<n;i++)
			scanf("%d",&a[i]);
		cal(n,a);//由于指针的帮助,函数可以直接调用且不需要返回值
		printf("%d\n",abs(a[n-2]-a[1]));//输出调用函数cal,传递数组大小和数组
	}
	return 0;
}

问题 C: 幂字符串

序号:1193

题目描述

给你一个字符串,请你判断将此字符串转化成a^n形式的最大的n是多少。
例如:abcd=(abcd)^1,则n=1;
aaaa=a^4,则n=4;
ababab=(ab)^3,则n=3。

输入

输入包含多组测试数据。每组输入为一个字符串,长度不超过100,其中不包含空格等空白符。当输入为一个“.”时,输入结束。

输出

对于每组输入,输出将此字符串转化成a^n形式的最大的n。

样例输入
abcd
aaaa
ababab
.
样例输出
1
4
3
思路过程:

​ 题目较为复杂,我们先仔细读题

对于每组输入,输出将此字符串转化成a^n形式的最大的n。

​ 就是说要找最可能作为底数的a和a重复了的次数n。再看输入,以’.'结束,输出为一行一个,简单可以解决

	while(strcmp(gets(s),".")!=0)
		printf("%d\n",cal(s));

​ 然后就是函数了,我们自定义函数cal,传递s地址,对字符串s折中处理,然后取步长进行判断,用到了多个for循环,最后循环结束,返回字符串s长度与取的步长的商。较为复杂,贴上代码供参考理解。

Example Answer:
#include <stdio.h>
#include <string.h>

int cal(char *s)
{
    int i,j,k;
    for(i=1;i<=strlen(s)/2;i++)//折中处理
    {
        if((strlen(s)%i)!=0) continue;
        for(j=0;j<i;j++)
        {
            k=j+i;
            while(k<strlen(s)&&s[k]==s[j])
                k+=i;
            if(k<strlen(s)) break;
        }
        if(j==i) break;
    }
	return strlen(s)/i;//返回字符串长度与步长的商即为n
}

int main()
{
    char s[50];
    while(strcmp(gets(s),".")!=0)//比较字符串
		printf("%d\n",cal(s));//调用函数
    return 0;
}

小结:

本次题目较前几次题目相比至少在所学内容之内了,都是可做的题目,但是更加侧重于考验算法思维, 问题ABC难度在递增,但代码长度越来越短?算法主要是考思路思维,代码实现其实只是一个小问题 。希望同学们勇于尝试,积极钻研,这样对C的学习会很有帮助!

本次的讲解是最细致的一次了,回顾了以前学到的内容,不理解的同学可以借机补习起来,这个卡口一过,自身的算法能力会有很大的提升!

如果有问题或者错误请见谅并联系我改正!一起努力学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值