【PAT】B1048 数字加密

 

题目描述

本题要求实现一种数字加密方法。首先固定一个加密用正整数 A,对任一正整数 B,将其每 1 位数字与 A 的对应位置上的数字进行以下运算:对奇数位,对应位的数字相加后对 13 取余——这里用 J 代表 10、Q 代表 11、K 代表 12;对偶数位,用 B 的数字减去 A 的数字,若结果为负数,则再加 10。这里令个位为第 1 位。

输入格式:

输入在一行中依次给出 A 和 B,均为不超过 100 位的正整数,其间以空格分隔。

输出格式:

在一行中输出加密后的结果。

输入样例:

1234567 368782971

输出样例:

3695Q8118

 首先贴出菜鸡的代码(至今存在测试用例错误,6个测试用例只通过4个,欢迎指出代码中的不足)

#include <iostream>
using namespace std;
int main(){
	string a,b;
	cin>>a>>b;
	int max,min;
	int len_a=a.length();
	int len_b=b.length();
	
	if(len_a>len_b){
		max=len_a;
		min=len_b;
	}
	else{
		max=len_b;
		min=len_a;	
	}
	char c[max+1];
	for(int j=0;j<len_a;j++){  //反转数组1,且时间复杂度很高
		int temp_a=a[len_a-1];
		for(int i=len_a;i>=2+j;i--){
			a[i-1]=a[i-2];
		}
		a[j]=temp_a;
	}
	
	for(int j=0;j<len_b;j++){  //反转数组2,且时间复杂度很高
		int temp_b=b[len_b-1];
		for(int i=len_b;i>=2+j;i--){
			b[i-1]=b[i-2];
		}
		b[j]=temp_b;
	}
	for(int i=0;i<max;i++){
		if(i%2==1){
				if(i<min){
				int temp=(b[i]-'0')-(a[i]-'0');  //因为直接字符串相减出现的问题1
				if(temp<0){
					temp=(temp+10);
				}
				c[i]=temp+'0';	//因为直接字符串相减出现的问题2
			}
			else if(i>=min){
				if(len_a>len_b){
					c[i]=a[i];
				}
				else if(len_a<len_b){
					c[i]=b[i];
				}
			}
		}
		else if(i%2==0){//奇数位 
			if(i<min){
				int temp=(a[i]-'0'+b[i]-'0')%13;  //因为直接字符串相减出现的问题3
				if(temp<10){
					c[i]=temp+'0';    //因为直接字符串相减出现的问题4
				}
				else if(temp>=10&&temp<=12){
					if(temp==10){
						c[i]='J';
					}
					else if(temp==11){
						c[i]='Q';
					}
					else if(temp==12)
						c[i]='K';
				}
			}
			else if(i>=min){
				if(len_a>len_b){
					c[i]=a[i];
				}
				else if(len_a<len_b){
					c[i]=b[i];
				}
			}
		
		}
	}
	for(int j=0;j<max;j++){  //反转数组3,且时间复杂度很高
		int temp=c[max-1];
		for(int i=max;i>=2+j;i--){
			c[i-1]=c[i-2];
		}
		c[j]=temp;
	}
	for(int i=0;i<max;i++)
		cout<<c[i];
	return 0;
} 

 代码很长,标记了一些重复性的地方,错的多的地方,留待未来回顾的时候提醒自己哪些地方自己错的比较多、作了重复的东西。首先讲一下个人那道题目的思考,第一步我看到输入样例的时候直观的把A、B两个数定义为字符串(不知道这个习惯有哪些问题,看一些博主和参考书上第一位数组,虽然本质上两者类似),然后,就按正常的逻辑思路,在反转数列这里吸取第一个教训——没有把常用功能段用以函数的形式固定下来以及第二个教训——for循环的时间复杂度可以减少。在字符转换的过程中,迎来了第三个教训——忘记了字符数字和整型数字的转化,白白浪费很多时间。综合来书还有第四点教训——没有优化好代码。

经验教训

  1. 明知道后面还有需要用到反转的地方,却没有用函数固定下来,重复的做一些类似的工作,增加代码的长度和内存。
  2. 在用到反转数组功能的地方,可以把时间复杂度变可以从O(n^2)为O(n),这是刷题不足的表现。
  3. 字符型数字和整型数字不同,字符型数字在ASCLL码中有编号,字符型数字变为整型数字可以表示为(c-'0'),整型数字变为字符型数字则可以表示为(c+'0'),c[0,9],c\in\mathbb{N}
  4. 其实在做题的时候,多花点时间琢磨一下流程和优化一下算法,在编码过程中可以减少编码的时间、编码过程中逻辑混乱带来的时间浪费以及回过头来修改代码的理解度。这三个时间的累加完全超过了编码前整理思路和优化算法的时间。在考试竞赛中尤为突出。

参考代码

下面给出参考代码,无论实在空间复杂度还是时间复杂度上都优化了本人上面的代码。留作参考: 

#include <cstdio>
#include <cstring>
 const int maxn=110;
 char a[maxn],b[maxn],c[maxn];
 void reverse(char s[]){  //将常用的代码以函数的形式固定下来方便调用
 	int len=strlen(s);
 	for(int i=0;i<len/2;i++){
 		int temp=s[i];
 		s[i]=s[len-1-i];
 		s[len-1-i]=temp;
	 }
 }
 int main(){
	scanf("%s %s",a,b);
 	reverse(a);
 	reverse(b);
 	int lenA=strlen(a);
 	int lenB=strlen(b);
 	int len=lenA>lenB?lenA:lenB;
 	for(int i=0;i<len;i++){
 		int numA=i<lenA?a[i]-'0':0;  //优化了算法,减少了重复量
 		int numB=i<lenB?b[i]-'0':0;
 		if(i%2==0){
 			int temp=(numA+numB)%13;
 			if(temp==10) c[i]='J';
 			else if(temp==11) c[i]='Q';
 			else if(temp==12) c[i]='K';
 			else c[i]=temp+'0';
		 }
		 else{
		 	int temp=numB-numA;
		 	if(temp<0) temp=temp+10;
		 	c[i]=temp+'0';
		 }
	 }
	 reverse(c);
	 puts(c);
	 return 0;
 }

猜你喜欢

转载自blog.csdn.net/xt199711/article/details/86683265