PAT(Basic Level)Practice(中国語)1014


1014ホームズのデート(20分)
大探偵ホームズは奇妙なメモを受け取った.
デートしよう!3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm.
大探偵はすぐに分かった.メモの奇妙な文字化けしは実際にデートの時間である木曜日14:04で、前の2つの文字列の1対目の同じ大文字の英語のアルファベット(大文字と小文字が区別されている)は4番目のアルファベットDで、木曜日を代表しているからだ.2番目の同じ文字はEで、それは5番目の英語のアルファベットで、1日の14時間目を表しています(1日の0時から23時まで数字の0から9、および大文字のAからNで表されています).後の2つの文字列の1対目の同じ英字sは、4番目の位置(0からカウント)に現れ、4分目を表す.2対の文字列が与えられ、ホームズがデートの時間を復号するのを助けてください.
≪フォーマットの入力|Input Format|oem_src≫:4行に4つの空白ではなく、スペースを含まず、長さが60を超えない文字列を入力します.
出力フォーマット:一行の中でデートの時間を出力して、フォーマットはDAY HH:MMで、その中のDAYはある週の3文字の略語で、つまりMONは月曜日を表して、TUEは火曜日を表して、WEDは水曜日を表して、THUは木曜日を表して、FRIは金曜日を表して、SATは土曜日を表して、SUNは星期日を表します.問題入力は、各テストに一意の解があることを保証します.
サンプルを入力:
3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm
出力サンプル:
THU 14:04
										    

実際にはこの問題は難しくなく、本質的には簡単な文字検索の比較出力にすぎないが、問題の記述は少し混乱している.特に2番目の条件の「2番目のペアが同じ文字」は、最初から最後まで比較した2番目のペアなのか、それとも最初の条件に基づいた2番目のペアなのか.テストの結果、最初の条件に基づいた2番目のペアであることが分かった.この点を理解してから、問題を解き始めます.
私は問題を作る時に考えが乱れて、そこで以下のいくつかのやり方を生んで、次に私の各種の奇抜なやり方を分析しましょう!それでも、それぞれのやり方の本質は簡単な比較です.私たちが採用しているコンパイラはg++6.5.0バージョンです.注意この問題はcout出力cinを使用してタイムアウトを防止しないでください.また文字列を読み込むにはgetsという不安全な関数を使わず、そのまま廃棄してください.本博文の末尾には、代替的な書き方が記載されています.
										  1
#include 
int main()
{
    char date[4][61];
    int day,hour,min;
    char week[7][4] = {
        "MON","TUE","WED",
        "THU","FRI","SAT",
        "SUN"
    };
    int count = 1;
    
    scanf("%s%s%s%s", date[0], date[1], date[2], date[3]);
    for(int i = 0;date[0][i] != '\0' && date[1][i] != '\0';i++)
    {
        if(date[0][i] >= 'A' && date[0][i] <= 'G' && date[0][i] == date[1][i] && count == 1)
        {
            day = date[0][i]-'A';
            ++count;
        }
        else if(count == 2 && date[0][i] == date[1][i] && (date[0][i] >= '0' && date[0][i] <= '9' || date[0][i] >= 'A' && date[0][i] <= 'N'))
        {
            if(date[0][i] >= '0' && date[0][i] <= '9')
                hour = date[0][i]-'0';
            else
                hour = date[0][i]-'A'+10;
            break;
        }
    }
    for(int i = 0;date[2][i] != '\0' && date[3][i] != '\0';i++)
    {
        if((date[2][i] >= 'a' && date[2][i] <= 'z' || date[2][i] >= 'A' && date[2][i] <= 'Z') && date[2][i] == date[3][i])
        {
            min = i;
            break;
        }
    }
    printf("%s %02d:%02d", week[day], hour, min);
    
    return 0;
}

まず、このやり方の利点についてお話しします.まず、このやり方の意図が明確で、それぞれ3組の時間(そのうちdayは下付き)を求め、出力を集中し、dayの取得にはA-Gの範囲に限定する必要があることに注意します!!hourは0-9またはA-Nの範囲内でなければなりません!!!「演算子の優先度が低い」&&&」という小さな詳細は、カッコで囲む必要があります.そうしないと、入力エラーが発生しやすくなります.このやり方の欠点も明らかにプログラムがやや冗長であるが,実際にはヘッダファイルを増やすことで一部のプログラムを書き換えることができる.
										  1  
#include 
#include 
int main()
{
    char date[4][61];
    int day,hour,min;
    char week[7][4] = {
        "MON","TUE","WED",
        "THU","FRI","SAT",
        "SUN"
    };
    int count = 1;
    
    scanf("%s%s%s%s", date[0], date[1], date[2], date[3]);
    for(int i = 0;date[0][i] != '\0' && date[1][i] != '\0';i++)
    {
        if(date[0][i] >= 'A' && date[0][i] <= 'G' && date[0][i] == date[1][i] && count == 1)
        {
            day = date[0][i]-'A';
            ++count;
        }
        else if(count == 2 && date[0][i] == date[1][i] && (isdigit(date[0][i]) || date[0][i] >= 'A' && date[0][i] <= 'N'))
        {
            if(isdigit(date[0][i]))
                hour = date[0][i]-'0';
            else
                hour = date[0][i]-'A'+10;
            break;
        }
    }
    for(int i = 0;date[2][i] != '\0' && date[3][i] != '\0';i++)
    {
        if(isalpha(date[2][i]) && date[2][i] == date[3][i])
        {
            min = i;
            break;
        }
    }
    printf("%s %02d:%02d", week[day], hour, min);
    
    return 0;
}

大まかな解析では時間複雑度はO(n)であり,cinとcoutを用いないとタイムアウトしない.
										    

この方法は各グループで結果を得た後に直接出力する.
#include 
#include 
int main()
{
    char date[4][61];
    int i;
    int len1,len2,len3,len4;
    char week[7][4] = {
        "MON","TUE","WED",
        "THU","FRI","SAT",
        "SUN"
    };
    
    scanf("%s%s%s%s", date[0], date[1], date[2], date[3]);
    len1 = strlen(date[0]);
    len2 = strlen(date[1]);
    len3 = strlen(date[2]);
    len4 = strlen(date[3]);
    for(i = 0;i < len1 && i < len2;i++)
    {
        if(date[0][i] == date[1][i] && date[0][i] >= 'A' && date[0][i] <= 'G')
        {
            printf("%s ", week[date[0][i]-'A']);
            break;
        }
    }
    for(i++;i < len1 && i < len2;i++)
    {
        if(date[0][i] == date[1][i])
            if(date[0][i] >= '0' && date[0][i] <= '9')
            {
                printf("%02d:", date[0][i]-'0');
                break;
            }
            else if(date[0][i] >= 'A' && date[0][i] <= 'N')
            {
                printf("%d:", date[0][i]-'A'+10);
                break;
            } 
    }
    for(i = 0;i < len3 && i < len4;i++)
        if(date[2][i] == date[3][i] && (date[2][i] >= 'a' && date[2][i] <= 'z' || date[2][i] >= 'A' && date[2][i] <= 'Z'))
        {
            printf("%02d", i);
            break;
        }
    
    return 0;
}

このやり方は上のやり方と時間的には大きな違いはありませんが、もっときれいで美しく、私個人的には解法2に傾いています.
								  gets()  !!!!

まず、gets関数がなぜ安全ではないのかについて説明します.私たちのプログラムの読み込みは入力ストリームの形式で、私たちが1つの文字配列の容量が10であると仮定しますが、gets関数が読み込んだ文字の長さは往々にして不確定です.この場合、あるストリームの長さが10を超えると、余分な部分が配列の範囲を超え、コンピュータ内の残りのデータに対して消去の危険性があります.これは場合によっては災難的である.したがってC 11はgets関数を直接強硬に廃棄した.strcpyのような関数にもセキュリティ上の危険性がありますが、なぜ廃棄されないのでしょうか.これはstrcpyの操作がプログラマーによって決定されるためであり,C言語ではプログラマー自身がプログラムの安全性を保証することが要求され,gets関数の不安全性はプログラマーではなくプログラムを使用するユーザから来ている.
							         gets()  

1.scanf()は、スペースまたは改行などの空白文字で区切られた複数の文字列またはスペースを含まない文字列、例えば、上題に4つの文字列を読み込み、各文字列を改行で分割することで、このように読み込むことができます.このような実現可能性は、scanf関数が1つの文字列に対して1番目の空白文字から2番目の空白文字まで読み込むことである.(%c読み込み時は特殊で、空白文字が読み込まれます)
2.fgets()関数文字列を読み込むには、3つのパラメータが必要です.フォーマット:fgets(文字列ヘッダアドレス、文字列最大長、ファイル読み込み)一般的にPTAでは、このように書きます(文字列がchar str[15]):fgets(str,14,stdin).fgets()関数は存在する可能性のある改行文字を保存することに注意し、タイトルが各文字列が改行文字で終わることを示す場合、上記の例はchar str[16]、fgets(str,15,stdin)、str[14]='0'に変更すべきであり、改行文字が1つのビットを占有しているためである.stdinの意味ではstandard input(標準入力).fgets()関数の例については、ブロガーの博文PTA乙級が反対のことを言うのを見ることができます.