2022年10月30日日曜日

文字列の検索・操作、文字列についての条件判定、アスキーコード、正規表現(1)


文字列の最後の文字

ABC244-A

問題概要

長さnの文字列sの最後の文字を出力せよ。

解答

n=gets.to_i
s=gets.chomp
puts s[n-1]
    

このときは本番不参加。Cで書いたのが以下。

#include<stdio.h>
#include<stdlib.h>
#define N 6
#define N2 1002
int main(void){
    char* s=(char*)malloc(sizeof(char)*N);
    if(s==NULL){
        printf("memory allocation to s failed\n");
        exit(1);
    }
    char* ts1=fgets(s,N,stdin);
    if(ts1==NULL){
        printf("fgets(s) failed\n");
        exit(1);
    }
    int n=readint(s);
    free(s);
    char* s2=(char*)malloc(sizeof(char)*N2);
    if(s2==NULL){
        printf("memory allocation to s2 failed\n");
        exit(1);
    }
    char* ts2=fgets(s2,N2,stdin);
    if(ts2==NULL){
        printf("fgets(s2) failed\n");
        exit(1);
    }
    printf("%c\n",*(s2+n-1));
    return 0;
}
int readint(char *s){
    int i=0,ret=0;
    while(*(s+i)>=48 && *(s+i)<=57){
        ret*=10;
        ret+=*(s+i)-48;
        i+=1;
    }
    return ret;
}
    

文字列についての条件判定

ABC249-B

問題概要

与えられた文字列が、次の条件を満たすか否か判定せよ。

  1. 英大文字が少なくとも一つある。
  2. 英小文字が少なくとも一つある
  3. 全ての文字が相異なる

以下が本番の提出コード

s=gets.chomp
flag=true
if s.downcase==s
    flag=false
end
if s.upcase==s
    flag=false
end
s=s.split("").to_a
su=s.uniq
if s.size!=su.size
    flag=false
end
if flag==true
    puts "Yes"
else
    puts "No"
end
    

問題の条件は、以下の命題が全て成り立つことと同値である。

  1. 与えられた文字列の文字を全て全て大文字に変換したものが元の文字列に一致しない。
  2. 与えられた文字列の文字を全て全て小文字に変換したものが元の文字列に一致しない。
  3. 与えられた文字列から重複する文字を取り除いた文字列の長さが、元の文字列と同じである

本番ではこの置き換えた条件を使ってコードを書いたわけだが、より素直に、問題で与えられた条件をそのまま使ってコードを書いてもいいだろう。すると次のようになる。

s=gets.chomp.split("")
if !s.any?{|char| char.ord>=65 && char.ord<=90}
    puts "No"
    exit
end
if !s.any?{|char| char.ord>=97 && char.ord<=122}
    puts "No"
    exit
end
ref=Array.new(123,false)
s.each do |char|
    if ref[char.ord]==true
        puts "No"
        exit
    end
    ref[char.ord]=true
end
puts "Yes"        
    

「同じ文字が繰り返されていないか」の判定部分では、文字のアスキーコードをインデックスとする配列を作り、全てfalseで初期化。文字列を前から見ていって、出てきた対応するアスキーコードの所をtrueに。もしその文字のところがすでにtrueになっていたら、先にその文字が出てきていたということなので、"No"を出力して終了している。

ところで、「少なくとも1つが小文字」ではない⇔「全てが大文字」であるから、以下のようにしても論理的には等価なはずなのだが、なぜかこちらはうまく動かない。

if s.all?{|char| char.ord>=65 && char.ord<=90}
puts "No"
exit
end
if s.all?{|char| char.ord>=97 && char.ord<=122}
puts "No"
exit
end    

Cで書いたのが以下。

#include<stdio.h>
#include<stdlib.h>
#define N 101
int main(void){
    char* s=(char*)malloc(sizeof(char)*N);
    fgets(s,N,stdin);
    int flag1=0;
    int flag2=0;
    int flag3=1;
    for (int i=0;i<N;i++){
        if ((int)*(s+i)>=65 && (int)*(s+i)<=90)flag1=1;
        else if ((int)*(s+i)>=97 && (int)*(s+i)<=122)flag2=1;
        else break;
        for(int j=i+1;j<N;j++){
            if((!*(s+j)>=65 && *(s+j)<=90) || (!*(s+j)>=98 && *(s+j)<=122))break;
            else if (*(s+j)==*(s+i)){
                flag3=0;
                break;
            }
        }
        if(flag3==0){
            break;
        }
    }
    if (flag1==1 && flag2==1 && flag3==1)printf("Yes\n");
    else printf("No\n");
    return 0;
}
    

0 件のコメント:

コメントを投稿