A1060 Are They Equal (25分)

如何判断两个串是否相等?

如图所示,观察题目给的 sample。只要红色方框和红色圈圈中这两部分内容相同那就可以下结论这两个串相等,其中:

红色方框内容比较直观,就是从第一个有效位开始至到 n 位

而红色圈圈内容可能不太容易看出,但其实是和第一个有效位以及小数点有关的,这里就是「小数点 - 第一个有效位」

 

思路如下

/* 伪码 */
// 第一部分:遍历两个串,分别找出小数点、第一个有效位,并且保存需要打印的 n 位有效位
for (遍历两串) {
    if (是小数点吗)    {记录小数点位置}
    else if (遇到第一个有效值了吗)    {记录第一个有效位位置}
    else if (两串当前都是有效值吗)    {使两串都找到有效位}
    
    if (两串均未找到有效位)    {继续遍历,继续找}
    else if (两串均找到有效位)    {保存映像}
    else if (一个找到有效位,另一个没有)    {保存找到有效位的串的映像}
}
while (两串是否未找完)    {继续找小数点、第一个有效位; 或保存有效位映像}
if (两串遍历完了还未找到小数点)    {小数点即末尾}

// 第二部分:判断两个串是否相等以及输出
计算指数();

if (两串映像相等 && 指数相等)    {按相等格式输出}
else    {按不相等格式输出}

 

第一部分遍历最根本的思路就是,每遍历一个字符去判断是否 '.' 、'0' 或 '1'~'9'

// 找小数点
if (*it == '.')   poi = i;//记录小数点位置
// 找第一个有效值, flag 标识"第一个"
if (*it != '0' && !flag)    { dig = i; flag = true; }
// 找到两个串当前字符都是有效位
for (; it1 != s1.end() && (*it1 == '0' || *it1 == '.'); ++it1);
for (; it2 != s2.end() && (*it2 == '0' || *it2 == '.'); ++it2);

我希望能一次遍历找完所有的数据:小数点有效值需要打印的 n 个字符。所以每次遍历还需要判断当前字符是否是有效值,是就需要保存起来,到时候直接拿出这个串打印就行了

if (两串迭代器均未找到第一个有效值)    continue;
else if (两串迭代器当前都是有效值) {
    img1 = img1 + *it1;//将 str 需要打印的 n 个字符保存到 img
    img2 = img2 + *it2;
} else if (两串迭代器一个已找到第一个有效值,另一个还未找到) {
    if (*it1 未找到第一个有效值)    img2 = img2 + *it2;
    else    img1 = img1 + *it1;
}

总结一下第一部分前半部分的 for() :

for() {
    // 找小数点
    if (*it == '.')   poi = i;//记录小数点位置
    // 找第一个有效值, flag 标识"第一个"
    if (*it != '0' && !flag)    { dig = i; flag = true; }
    // 找到两个串当前字符都是有效位
    for (; it1 != s1.end() && (*it1 == '0' || *it1 == '.'); ++it1);
    for (; it2 != s2.end() && (*it2 == '0' || *it2 == '.'); ++it2);

    // 保存有效值
    if (两串迭代器均未找到第一个有效值)    continue;
    else if (两串迭代器当前都是有效值) {
        img1 = img1 + *it1;//将 str 需要打印的 n 个字符保存到 img
        img2 = img2 + *it2;
    } else if (两串迭代器一个已找到第一个有效值,另一个还未找到) {
        if (*it1 未找到第一个有效值)    img2 = img2 + *it2;
        else    img1 = img1 + *it1;
    }
}

但是有些情况比如「 12 和 12.013 输出三位」,第一个串 "12" 遍历完了第二个串 "12.013" 还没有,所以后面需要把未遍历完的串继续遍历,还是找小数点、第一个有效位(如果未找到)以及剩余需要输出的字符,这就是文章开头伪码后半部分的 while() 要做的事,只不过我这里换成 for() 了,其实都是一样的

第一部分后半部分

if (it1 != s1.end() || it2 != s2.end()) {
    for (; it1 != s1.end(); ++it1, ++i) {
        if (*it1 == '.')    poi1 = i;//找小数点
        else if (*it1 != '0' && !flg1)    { dig1 = i; flg1 = true; }//找第一个非零值
        else if (img1.size() < (unsigned)n)    img1 = img1 + *it1;//除去'.'以及第一个非零值,其他值都保存映像
    }
    for (; it2 != s2.end(); ++it2, ++j) {
        if (*it2 == '.')    poi2 = j;
        else if (*it2 != '0' && !flg2)    { dig2 = j; flg2 = true; }
        else if (img2.size() < (unsigned)n)    img2 = img2 + *it2;
    }
}

注意啦并不是遍历完两个串就完了,像上面「 12 和 12.013 输出三位 」这个例子,“12” 是遍历完了,但目前只保存了两个待输出的字符,还需要填充 '0' 才可以输出;另外有些情况就算遍历完整个串都可能找不到小数点,比如「 12345 和 12346 」这种整数,但其实这种情况小数点就是末尾。所以遍历完了全部两个串还需要做一些工作来 “收尾” XD:

while (img.size() < (unsigned)n)    img = img + '0';//不够的映像填'0'
if (it == s.end() && poi仍未找到)    poi = s.size();//如果遍历完了都没有小数点,那小数点就在最后面

这样第一部分就完成了

 

第二部分主要内容有两个,第一个是计算指数,第二个是封装一个打印函数,都比较简单。值得一提的是计算指数,当第一个有效位在小数点前面则指数为正,如「12300 、123.45」;当小数点在第一个有效位前面指数可能为 0,如「0.123、0.666」也可能为负,如「0.00001 、0.072」,简单试一试就可以归纳出规律了,所以第二部分略了 ;-)

 

附上测试数据

3 12300 12358.9
3 120 128
3 12 12.012
3 00013 13024
3 0000.0 0012.3
3 000.0 00000
3 0.0 0000.0
3 0.12340 0.00123
晴神数据
4 0000 0000.00
4 00123.5678 001235
3 0.0520 0.0521
4 00000.000000123 0.0000001230
4 00100.00000012 100.00000013
5 0010.013 10.012
4 123.5678 123.5
3 123.5678 123
4 123.0678 123
3 0.000 0
12 123456789012345 123456789012300
12 123456789012345 123456789010000

 

完整代码点击此处

posted @ 2021-01-31 15:48  幼麟  阅读(49)  评论(0编辑  收藏  举报