PTA-BasicLevel-1003 我要通过!

4 篇文章 0 订阅
本文详细分析了PAT基础级1003题目的解题思路,重点在于理解并实现字符串“答案正确”的条件判断。作者首先介绍了题目要求,然后逐步解析第三个条件的意义,并通过实例说明如何进行转化。最后,提出了两种解题方法,并展示了基于条件分析的解题代码实现,强调了代码实现主要基于分析和推导。
摘要由CSDN通过智能技术生成

PTA-BasicLevel-1003 我要通过!

大一新生,编程菜鸡,仅仅作为个人笔记,轻喷
所用平台:macOS 编程IDE:Xcode

题目详情:“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。

输入格式:
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。

输出格式:
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。

具体要求分析

要求输入一个字符串,判断其正确与否
要求如下:
1: 要求输入的字符串有且仅有 P A T 三个字符
2:任何形状入 xPATx (其中x为 仅有一个或多个A组成的字符串,或者是 空字符串 空字符串不等价于空格! 以下不在做解释)
3:如果 aPbTc是正确的,那么 aPbATca 也是正确的。

注意:能否正确理解第三个条件是能否拿满分的关键!

第三个条件分析:

题目中的第三个条件是一个充分条件
(即 如果 p 是正确的 既可以推出 q是正确的 ,以下不做解释)
那么会存在一个问题我们会如何确定p是正确的呢?
那就要用到1,2两个条件,所以第三个条件的作用是将不能直接用1,2条件判断的进行转化(以下把第三个条件称为转化),转化为 1,2可以判断的

那么我们仔细研究一下转化是如何进行的呢?
由条件 我们发现 在往前推的时候
1:a是不变的
2:b少了一个 A
3:c少了一个 a

例如我们要判断一个字符串
APAAATAA
(在本题目中,我们将P称为前面的A,P与T中间的A称为中间的,T后面称为后面的A,以下不在解释)
首先字符串满足 1,但是不满足2,我们开始用3开始转化
我们可以确定 a 是 一个 A
所以 c 是 一个 A
所以有 APAATA > APAAAPAA (其中 > 这个符号代表充分条件)
我们会发现 我们还是无法直接判断 APAATA 这个字符串的正确性,那么也就意味着我们还需要在用一次转化,
APAT > APAATA > APAAATAA
我们发现这个字符串是错的 因为 2要求前后的a的数量相等,而这个例子显然不想等

OK至此,我们已经基本理清楚了如何判断一个字符串是否正确
现在有两种方法来解题:
1:让程序模拟我们的方法,进行判断
2:我们在其中发现规律

实不相瞒在更加复杂的题目题目中1可能是一个更加好的解决方案,但是在本题中我们可以较为容易的得出 前 中 后 三个A的关系

我们不妨假设有 中间有 b 个 A
如果要用条件 2 就必须进行 (b-1)转化
也就是 后面要减去 (b-1)*a 的A
并且做完以后还要 前后数量相等
那么我们就可以得出表达式
c - (b - 1) * a == a

那么大功告成,可以开始写代码了!!!

整体规划
函数声明:
//主函数 复杂输入字符串 调用判断函数 输出等操作
int main();
//判断函数 负责判断字符串对错
int judge(char exam[101]);
主要变量声明
//用于存放输入的字符串 题目中最长为 100 个 我们给101个
char exam[101];
//用于存放长度
int count;
具体过程实现
main 函数
int main(int argc, const char * argv[]) {
    
    //k存放判断例子的多少
    int k;
    scanf("%d",&k);
    
    //循环判断
    for (int i = 0; i < k; i++) {
        //清空字符串
        memset(exam,'\0',101);
        //输入串
        scanf("%s",exam);
        //求长度
        count = (int)strlen(exam);
        //利用自定义函数循环求解
        if (judge(exam) == 1) {
            printf("YES\n");
        }else {
            printf("NO\n");
        }
    }
    return 0;
}
judge函数
int judge(char exam[101]){
    //标识符定义 P,T_signal用于判断是否有P,T。 front_A,...用于统计A的数量分别为前中后
    int P_signal = 0,front_A = 0,middle_A = 0,latter_A = 0,T_signal = 0;
    for (int i = 0; i < count; i++) {
        
        //判断是否为 P A T
        if ((exam[i] != 'P') && (exam[i] != 'A') && (exam[i] != 'T')) {
            return 0;
        }
        
        //重复P T 是否出现P 和 T
        if (exam[i] == 'P' && P_signal) {
            return 0;
        }
        if (exam[i] == 'P' && T_signal) {
            return 0;
        }
        
        //P T 标识符  P T 出现顺序是否有误
        if (exam[i] == 'P') {
            P_signal = 1;
        }else if(exam[i] == 'T'){
            if ((P_signal == 0 )|| (latter_A + middle_A == 0)) {
                return 0;
            }
            T_signal = 1;
        }
        
        //统计 前 中 后 A的数量
        if ((!P_signal) &&(exam[i] == 'A') && !T_signal) {
            front_A ++;
        }else if(P_signal && (!T_signal) &&(exam[i] == 'A')){
            middle_A ++;
        }else if((exam[i] == 'A') && (P_signal && T_signal)){
            latter_A ++;
        }
    }
    
    //没有没有完整的PAT字符串
    if (!(P_signal && T_signal && (latter_A + front_A + middle_A))) {
        return 0;
    //中间只有一个A 且 前面的A数量等于后面的A 那么正确
    }else if(middle_A == 1 &&(latter_A == front_A)){
        return 1;
    //中间大于一个A
    }else if(middle_A >= 2){
        //如果两边没有 就一定可以
        if (front_A + latter_A == 0) {
            return 1;
        }
        //两边有 满足我们给出的表达式就可以
        if (latter_A - (middle_A - 1) * front_A == front_A ) {
            return 1;
        }
    }else return 0;
    return 0;
}
代码总结:

总体来说代码实现主要基于分析和推倒,在拥有明确思路后解决这个问题并不难,主要难在第三个条件的分析。
代码并不够精剪,希望各位大佬指教

所有代码
//
//  main.c
//  1003
//
//  Created by LLONVNE on 2021/6/16.
//

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

char exam[101];
int count;

int judge(char exam[101]){
    //标识符定义
    int P_signal = 0,front_A = 0,middle_A = 0,latter_A = 0,T_signal = 0;
    for (int i = 0; i < count; i++) {
        
        //判断是否为 P A T
        if ((exam[i] != 'P') && (exam[i] != 'A') && (exam[i] != 'T')) {
            return 0;
        }
        
        //重复P T
        if (exam[i] == 'P' && P_signal) {
            return 0;
        }
        if (exam[i] == 'P' && T_signal) {
            return 0;
        }
        
        //P T 标识符
        if (exam[i] == 'P') {
            P_signal = 1;
        }else if(exam[i] == 'T'){
            if ((P_signal == 0 )|| (latter_A + middle_A == 0)) {
                return 0;
            }
            T_signal = 1;
        }
        
        if ((!P_signal) &&(exam[i] == 'A') && !T_signal) {
            front_A ++;
        }else if(P_signal && (!T_signal) &&(exam[i] == 'A')){
            middle_A ++;
        }else if((exam[i] == 'A') && (P_signal && T_signal)){
            latter_A ++;
        }
    }
    //没有没有完整的PAT字符串
    if (!(P_signal && T_signal && (latter_A + front_A + middle_A))) {
        return 0;
    //中间只有一个A
    }else if(middle_A == 1 &&(latter_A == front_A)){
        return 1;
    //中间有>@A
    }else if(middle_A >= 2){
        //如果两边没有 就一定可以
        if (front_A + latter_A == 0) {
            return 1;
        }
        //两边有
        if (latter_A - (middle_A - 1) * front_A == front_A ) {
            return 1;
        }
    }else return 0;
    return 0;
}

int main(int argc, const char * argv[]) {
    
    int k;
    scanf("%d",&k);
    
    for (int i = 0; i < k; i++) {
        //清空字符串
        memset(exam,'\0',101);
        //输入串
        scanf("%s",exam);
        //求长度
        count = (int)strlen(exam);
        //利用自定义函数循环求解
        if (judge(exam) == 1) {
            printf("YES\n");
        }else {
            printf("NO\n");
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值