7-49 Have Fun with Numbers(附带思路解析从无到有)

这篇博客讨论了一道编程题,该题要求检查翻倍一个给定的多位数后,其数字是否仍由原始数字组成。作者提到了使用字符数组存储输入,通过模拟乘法操作处理大数,并用额外的数组记录每位数字出现的次数以进行比较。在代码实现中,作者用C语言编写了一个doubleA函数来处理翻倍操作,并检查结果的位数和原始数字的位数是否一致。如果一致,则继续检查位数相同的条件下,每位数字出现的次数是否相同,从而判断是否输出Yes或No。

原题翻译

 

注意到123456789这个九位数字是由1到9的数字组成的,并且没有重复。翻倍后得到246913578,又一次得到了一个九位数字 ,也一样由1到9的数字组成,只不过排列方式有所不同。再翻倍一下啊看看会得到什么结果吧!

现在你应该利用这个性质,去多检查一下其他的数吧!也就是,翻倍一个给定的k位的数值,看看翻倍后的结果是不是由初始的数打乱排列后重新组成。

输入的要求:

每次输入一个测试案例,每个输入案例是正整数且位数不超过二十位。

输出的要求:

对于每个输入,如果输出的结果,是由初始输入的每位数字的重新组成,那么第一行输出"Yes",如果不是就"No",在第二行输出翻倍之后的结果。

Sample Input:

1234567899

Sample Output:

Yes
2469135798

感想 :

原本不太想写的,因为代码的思路主要是借鉴的别人,但是好记性不如烂笔头,而且有新的知识点(模拟乘法)。就再写一遍好了,会加上自己的详细注释。

思路:(模拟乘法)

对于这道题,数值太大了,二十位的数字。我一开始想的比较简单,因为没有做过大数的题目,我就想着用long型来保存输入,对输入做处理。结果显而易见,当输入的数值超过了long型长度之后,超过的位数上的数就不会被读取进去,结果处理完自然是错。

对于这道题,应该用字符数组比如:char input[ ] 来保存输入。数组的大小,就选择25就行了,事实上超过20就行

        对于输入的这个char型数组,我们要将他每一位从低到高保存在一个新的int型数组中,我将它命名为d1[ ], 紧接着,对这个d1[ ],做模拟乘法的操作,并且将结果从低到高的保存在d2[ ] 之中。这d1d2数组,保存着我们的结果,我们可以创建两个数组

        (我命名为checkdigit1 [ 10 ] checkdigit2 [10] ),分别检查d1 d2数组保存的数字的个数,如果个数相同我就输出yes不同我就输出No


上面是主要的思路,进去之后还要考虑的细枝末节,将在代码中呈现出来。


接下来我会按照我的思路,一点点写完代码,一段一段完成。

#include<stdio.h>
#include<string.h> 


int main(){
	char input[25];
	int d1[25]={0};d2[25]={0};
	int checkdigit1[10]={0},checkdigit2[10]={0};
	
	while(scanf("%s",input) != EOF)//循环驱动条件,依照我的理解来说是,会让我们每次输入都经过一次循环,输入就是循环的条件 
	{
		int len = strlen(input);//调用字符串函数,得到输入的数的位数。
		int i; 
		for(i=0;i<len;i++){
			//将从低位到高位赋值。
			 
			d1[i]=input[len-1-i]-'0';// input[]-‘0’其实就是做ascii码数值的相减。12345.。。。这些数字在ascii都是相邻的,比如‘1’-‘0’=1利用这个性质,赋值int数组 	
		} 
		doubleA() ;
	} 
    
    return 0;
}

处理完d1数组,接下来我要将翻倍结果保存在d2数组中,我写了一个doubleA函数,参数表里面要有什么呢?  要有要处理的d1,要改变结果的d2。模拟乘法是怎么样的?

 下图举了两个例子 一个存在进位carry , 一个不存在。我要做的就是这样,途中881 ,123就是d1 数组的数。低位乘以2的余数保存在对应的d2数组单元中。并且我会用一个carry 变量来保存进位。

doubleA的函数大概是这样:

void doubleA(int a[],int alen,int b[],int blen,int *isok) {
	int carry=0;
	int i;
	for(i=0;i<alen;i++){
		b[i]=(2*a[i]+carry)%10;
		carry=(2*a[i]+carry)/10;
	}
	if(carry){
		b[i]=carry;
		*isok=0;
	}
	
}

参数表里面,我除了引进了两个要做处理的数组,还引进了一个int 指针,是用于后面主函数做判断。发生了进位之后,比如我的输入是881,输出是1762,前后两者位数不一样,那肯定不符合题目要求,要输出NO的,所以我这里让isok=0,就是不太OK。因为题目要求,无论是yes还是NO都要输出翻倍的结果,所以这里也要把最后的进位保存下来,留待输出。

完整代码如下:

#include<stdio.h>
#include<string.h> 

void doubleA(int a[],int alen,int b[],int blen,int *isok);
int main(){
	char input[25];
	int d1[25]={0},d2[25]={0};
	int checkdigit1[10]={0},checkdigit2[10]={0};
	
	int isok=1;//接下来会做两个判断会遇到变0的考验,通过证伪来达到想要的结果 
	
	while(scanf("%s",input) != EOF)//循环驱动条件,依照我的理解来说是,会让我们每次输入都经过一次循环,输入就是循环的条件 
	{
		int len = strlen(input);//调用字符串函数,得到输入的数的位数。
		int i; 
		for(i=0;i<len;i++){
			//将从低位到高位赋值。
			 
			d1[i]=input[len-1-i]-'0';	// input[]-‘0’其实就是做ascii码数值的相减。12345.。。。这些数字在ascii都是相邻的,比如‘1’-‘0’=1利用这个性质,赋值int数组 	
		} 
		doubleA(d1,len,d2,len,&isok);
		if(isok){ 						//输出和输入的位数一致才做检测 
			for(i=0;i<10;i++){
				checkdigit1[d1[i]]++;
				checkdigit2[d2[i]]++;
			} 	
										// 用于记录d1、d2的0-9的个数 
			for(i=0;i<9;i++){
				if( checkdigit1[i]!=checkdigit2[i] ){
					isok=0;
					break;
										// 遍历check1 check2数组,上面若出现有个数不相同的情况就break,而且不OK。 
				}
					
			} 
		}
		
		if(isok){
			printf("Yes\n");
		} 
		else
		{
			printf("No\n");
		}
		
		if(d2[len]!=0)
			printf("%d",d2[len]);
		for(i=len-1;i>=0;i--){
			printf("%d",d2[i]);
		}
		
	} 
    
    return 0;
}

void doubleA(int a[],int alen,int b[],int blen,int *flag) {
	int carry=0;
	int i;
	for(i=0;i<alen;i++){
		b[i]=(2*a[i]+carry)%10;
		carry=(2*a[i]+carry)/10;
	}
	if(carry){
		b[i]=carry;
		*flag=0;
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值