PAT-ADVANCED1060——Are They Equal

版权声明:我的GitHub:https://github.com/617076674。真诚求星! https://blog.csdn.net/qq_41231926/article/details/83893986

我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED

原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805413520719872

题目描述:

题目翻译:

1060 它们是否相等

如果机器只能保存3位有效数字,则浮点数12300和12358.9被认为是相等的,因为它们都保存为0.123×10 ^ 5。现在给出一台机器上的有效位数和两个浮点数,你需要指出它们在该机器中是否被视为相等。

输入格式:

每个输入文件包含一个测试用例,它给出三个数字N,A和B,其中N(<100)是有效位数,A和B是要比较的两个浮点数。 每个浮点数都是非负数,不大于10 ^ 100,即总位数小于100。

输出格式:

对于每个测试用例,如果两个数字处理相等,则在一行中打印“Yes”,然后以标准形式编号为0.d [1] ... d [N] * 10 ^ k(d [1]> 0 除非数字是0);如果相等,则输出“NO”,然后是标准形式的两个数字。 所有数字由一个空格分隔,一行末尾没有多余空格。

扫描二维码关注公众号,回复: 4021681 查看本文章

注意:不考虑四舍五入。

输入样例1:

3 12300 12358.9

输出样例1:

YES 0.123*10^5

输入样例2:

3 120 128

输出样例2:

NO 0.120*10^3 0.128*10^3

知识点:字符串

思路:按整数部分是否为0来分情况讨论

写在前面:题目出得很烂,应该说,所有PAT上涉及这种数字格式转换的题目没有一题是说清楚题意的,PAT出题者的水平可见一斑。

先写几个坑点:

(1)题目的数字可能有前导0,即00123这种形式。

(2)题目中的数字可能出现0.000、1.000这种形式。

(3)即使指数是0,也要写出来。

(4)指数可以是负数,也就是说对于0.000012的情况,其结果不应该是0.000,而应该是0.120 * 10 ^ -4次。

题目的要求是将两个数改写为科学计数法的形式,然后判断它们是否相等。而科学计数法的写法一定是如下格式:0.a1a2a3... * 10 ^ e,因此只需要获取到科学计数法的本体部分a1a2a3与指数e,即可判定两个数在科学计数法形式下是否相等。

按整数部分是否为0来分情况讨论,即

(1)0.a1a2a3...

(2)b1b2...bm.a1a2a3...

现在来考虑这两种情况的本体部分与指数分别是什么(以下讨论均按有效位数为3进行)。对(1)来说,由于在小数点后面还可能跟着若干个0,因此本体部分是从小数点后第一个非零位开始的3位(即akak + 1ak + 2,其中ak是小数点后第一个非零位),而指数则是小数点与该非零位之间0的个数的相反数(例如0.001的指数为-2)。在分析清楚后,具体的代码实现逻辑也就成形了,即令指数e的初值为0,然后在小数点后每出现一个0,就让e减1,直到到达最后一位(因为有可能是小数点后全为0的情况)或是出现非零位为止。

然后来看(2)的情况,假设b1不为零。很显然,其本体部分就是从b1开始的3位,而指数则是小数点前的总位数m。具体实现中,则可以令指数e的初值为0,然后从前往后枚举,只要不到达最后一位(因为有可能没有小数点)或是出现小数点,就让e加1。

如何区分给定的数是(1)还是(2)呢?先去除所有的前导0,按去除前导0后的字符串的第一位是否是小数点来判断其属于(1)或是(2)。

由于需要让两个数的科学计数法进行比较,因此必须将各自的本体部分单独提取出来。比较合适的方法是,在按上面的步骤处理(1)时,将前导0、小数点、第一个非零位前的0全部删除,只保留第一个非零位开始的部分(即akak + 1ak + 2...)。在处理(2)时,将前导0、小数点删除,保留从b1开始的部分(即b1b2...bma1a2a3...)。这些删除操作可以在上面获取指数e的过程中同时做到(使用string的erase函数)。之后便可以对剩余的部分取其有效位数的部分赋值到新字符串中,长度不够有效位数则在后面补0。

最后只要比较本体部分和指数是否都相等,就可以决定输出“YES”或“NO”。

时间复杂度和空间复杂度的分析对本题来说意义不大。

C++代码:

#include<iostream>
#include<string>

using namespace std;

int n;	//有效位数

string deal(string s, int &e);

int main(){
	string s1, s2, s3, s4;
	cin >> n >> s1 >> s2;
	int e1 = 0, e2 = 0;	//e1,e2为s1与s2的指数
	s3 = deal(s1, e1);
	s4 = deal(s2, e2);
	if(s3 == s4 && e1 == e2){
		cout << "YES 0." << s3 << "*10^" << e1 << endl;
	}else{
		cout << "NO 0." << s3 << "*10^" << e1 << " 0." << s4 << "*10^" << e2 << endl;
	}
}

string deal(string s, int &e) {
	int k = 0;	//s的下标
	while(s.length() > 0 && s[0] == '0') {
		s.erase(s.begin());	//去掉s的前导零
	}
	if(s[0] == '.') {	//去掉前导零后是小数点,说明s是小于1的小数
		s.erase(s.begin());	//去掉小数点
		while(s.length() > 0 && s[0] == '0') {
			s.erase(s.begin());	//去掉小数点后非零位前的所有零
			e--; //每去掉一个0,指数e减1
		}
	} else {	//去掉前导零后不是小数点,则找到后面的小数点删除
		while(k < s.length() && s[k] != '.') {	//寻找小数点
			k++;
			e++;	//只要不碰到小数点就让指数e++
		}
		if(k < s.length()) {
			s.erase(s.begin() + k);	//把小数点删除
		}
	}
	if(s.length() == 0) {	//如果去除前导零后s的长度变为0,说明这个数是0
		e = 0;
	}
	int num = 0;
	k = 0;
	string res;
	while(num < n){	//只要精度还没有到n 
		if(k < s.length()){
			res += s[k++];
		}else{
			res += '0';
		}
		num++;
	}
	return res;
}

C++解题报告:

猜你喜欢

转载自blog.csdn.net/qq_41231926/article/details/83893986
今日推荐