C++写PTA BaseLevel题目——题1029

目录

首先,给出我的全通过的解答

解答过程

解题中的各种错误

总结


首先,给出我的全通过的解答

#include <iostream>
#include <cstring>
using namespace std;
int main(){
    char str_1[81];
    char str_2[81];
    char ret[80] = "\0";
    int num = 0; //累计缺失的字符数
    int _num = 0; //坏键个数
    cin >> str_1 >> str_2;
    for(int i = 0;str_1[i] != 0;i++){
        if(str_1[i] != str_2[i - num]){
            int chr = str_1[i];
            if(chr >= 'a'){
                chr += 'A' - 'a';
            }
            if(strchr(ret, chr) == nullptr){
                ret[_num++] = chr;
            }
            num++;
        }
    }
    for(int i = 0;i < _num;i++){
        cout << ret[i];
    }
}

解答过程

        先看题目,题目预设场景是键盘上有坏键,导致某个或某几个键敲击之后不产生输入。题目给出两个字符串,第一个表示敲击正常键盘应该输入的文字,第二个表示实际输入的文字,要求通过比较两个字符串的区别找出坏的键。

        输入限制:两个字符串非空,且包含总字符数不超过80,只由字母 A-Z(包括大、小写)、数字 0-9、以及下划线 _(代表空格)组成,题目保证必然有一个坏键存在。

        输出限制:在一行中输出坏键,英文字母只输出大写(很合理,毕竟键盘上不会存在A、a两个键,而大多数键盘用的是大写),每个坏键只输出一次,不需要用空格分隔。

        虽然写代码的过程中各种编译问题,各种逻辑BUG,但是全通过之后回过头来看,解答的思路还是挺清楚的,首先定义两个长度81的字符数组分别存储输入的两个字符串。然后是for语句逐个字符对比,变量num存储遇到的缺失字符,作为第二个字符串的下标偏移。简单回答一下为什么需要这么一个下标偏移,举个例子 "This" 和 "Tis" ,循环变量 i 为 1 的时候, str_1 指向了字母 h ,而 str_2 指向了字母 i ,很明显 h 就是坏键,由于第二个字符串缺失了字符,下一轮的比较第二个字符串指向的位置就不应变动,否则就会出现第一个字符串指向字母 i 而 第二个字符串指向字母 s ,导致将字母 i 也当成是坏键,而正确情况是,第一个字符串下标 +1 ,而第二个字符串下标不动,所以我们给第二字符串的下标加上个负的偏移量 num ,每次遇到坏键时 num + 1 。到这里我们实现了辨别坏键,为了实现坏键的输出,我们需要用一个字符数组 ret 存储坏键,因为按照题目要求,每个坏键只输出一次,所以不能每次遇见坏键即刻输出,为了防止重复,我们需要记忆遇到的坏键。每次遇到坏键,若 ret 中未出现过该键,则将该键存入 ret 中。最后,简单地将结果——字符数组 ret 逐个字符输出即可。

解题中的各种错误

        首先,第一次解答错误,问题还是蛮大的。前4个测试点都过了,如果没有第五个测试点。这里没有用 _num 来单独作为 ret 的下标,而是直接使用的 num 。当时想的是,ret 已经初始化了,除了 ret[0] 之外的其他元素都为 \0 ,这样尽管重复坏键不存入 ret 而 num 却在增加,相当于在 ret 中跳过了几个下标进行赋值,但是 \0 不输出任何字符,因此当时觉得这样做是可行的。结果发现在第一次遇到 \0 之后, 后面的元素都无法输出了,而且注意,我这里用的是逐个字符输出的方式,所以到底是什么原因导致的遇到 \0 之后后续元素无法输出的问题仍然未找到

#include <iostream>
#include <cstring>
using namespace std;
int main(){
    char str_1[81];
    char str_2[81];
    char ret[80] = "0";
    int num = 0;
    cin >> str_1 >> str_2;
    for(int i = 0;str_1[i] != 0;i++){
        if(str_1[i] != str_2[i - num]){
            if(strchr(ret, str_1[i]) == nullptr)
                ret[num] = str_1[i];
            num++;
        }
    }
    for(int i = 0;i < num;i++){
        if(ret[i] >= 'a'){
            ret[i] += 'A' - 'a';
        }
        cout << ret[i];
    }
}

         然后是第二次解答错误,这个错误的版本起始比第一次解答错误更接近正确的解答,但是只通过了两个得分为 1 的测试点,得分相比第一次惨不忍睹,让我想起网上的笑话:“软件能跑起来全靠这个BUG”。没错第一次解答能通过 4 个测试点完全是因为遇到 \0 之后后续元素无法输出这个问题掩盖了一个逻辑上的漏洞,那就是在遇到坏键时与之前记忆的坏键比较有无重复的问题,这里其实忽略了同一个字母的大小写问题,由于存入 ret 的时候是未做小写到大写的变换的,而是选择了在输出过程中做,所以可能会出现 a 存入 ret 中,尽管 A 在 ret 中已经存在。

#include <iostream>
#include <cstring>
using namespace std;
int main(){
    char str_1[81];
    char str_2[81];
    char ret[80] = "\0";
    int num = 0; //累计缺失的字符数
    int _num = 0; //坏键个数
    cin >> str_1 >> str_2;
    for(int i = 0;str_1[i] != 0;i++){
        if(str_1[i] != str_2[i - num]){
            if(strchr(ret, str_1[i]) == nullptr){
                ret[_num++] = str_1[i];
            }
            num++;
        }
    }
    for(int i = 0;i < _num;i++){
        if(ret[i] >= 'a'){
            ret[i] += 'A' - 'a';
        }
        cout << ret[i];
    }
}

总结

        呼~,总算是要码完了,码字的时间几乎快比得上我昨天对着没有编译器的电脑找问题的的时间了,第一次写文章,虽然不是什么复杂的东西,但把其中的逻辑一点一点地讲清楚还是蛮有挑战的一件事,要斟酌词句,表达清晰,回忆做题中的细节,而且这个过程要比找BUG有意思。

        总的来说,做这道题的时候出现了两个错误:第一个就是放任 \0 作为输出,导致了未知原理的错误—— \0 之后的元素全都无法输出;第二个是逻辑问题,没有在记忆坏键的时候进行大小写转换后再存入,而是选择在输出时进行转换后输出,导致了重复字母输出。

        最后,留下一个小问题来思考,我的代码中用的是下面这段代码中第一行来判断是否是小写字母,而我的本意是用第二行的语句的,但是我漏写了另一半的判断。尽管如此,在题目给定的输入条件下,这样写也不会有什么问题,反而因为少了一步判断效率会更高。

 if(ret[i] >= a)
 if(ret[i] >= a && ret[i] <= z)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值