字符串的简单应用

来源:互联网 发布:js原生tab切换 编辑:程序博客网 时间:2024/06/06 05:25

百练字符串习题解答:
百练:2742,2942,2974,2975,2743,1936,2818,2819,2820,2804,2797,2799.

1.百练2742:统计字符数

题目描述:
判断一个由a-z这26个字符组成的字符串中哪个字符出现的次数最多

题目链接:http://bailian.openjudge.cn/practice/2742

#include<cstring>#include<cstdio>#include<string>#include<iostream>using namespace std;int main(){    int n,a[30];    cin>>n;    while(n--)    {        string s;        memset(a,0,sizeof(a));        int maxl=0,ci;        cin>>s;        for(int i=0;i<s.size();i++)a[s[i]-'a']++;        for(int i=0;i<26;i++)        {            if(maxl<a[i]){maxl=a[i];ci=i;}        }        printf("%c %d\n",ci+'a',maxl);    }    return 0;}

2.百练2974:487-3279

题目描述
企业喜欢用容易被记住的电话号码。让电话号码容易被记住的一个办法是将它写成一个容 易记住的单词或者短语。例如,你需要给 Waterloo 大学打电话时,可以拨打 TUT-GLOP。 有时,只将电话号码中部分数字拼写成单词。当你晚上回到酒店,可以通过拨打 310-GINO 来向 Gino’s 订一份 pizza。让电话号码容易被记住的另一个办法是以一种好记的方式对号码 的数字进行分组。通过拨打 Pizza Hut 的“三个十”号码 3-10-10-10,你可以从他们那里订 pizza。
电话号码的标准格式是七位十进制数,并在第三、第四位数字之间有一个连接符。电话拨 号盘提供了从字母到数字的映射,映射关系如下: A, B, 和 C 映射到 2 D, E, 和 F 映射到 3 G, H, 和 I 映射到 4 J, K, 和 L 映射到 5 M, N, 和 O 映射到 6 P, R, 和 S 映射到 7 T, U, 和 V 映射到 8 W, X, 和 Y 映射到 9 Q 和 Z 没有映射到任何数字,连字符不需要拨号,可以任意添加和删除。 TUT-GLOP 的标 准格式是 888-4567,310-GINO 的标准格式是 310-4466,3-10-10-10 的标准格式是 310-1010。 如果两个号码有相同的标准格式,那么他们就是等同的(相同的拨号) 你的公司正在为本地的公司编写一个电话号码薄。作为质量控制的一部分,你想要检查是 否有两个和多个公司拥有相同的电话号码。

题目链接
http://bailian.openjudge.cn/practice/2974

问题分析
每读入一个字符串,将这个字符串作为一个字符型数组,依次判断每个数组元素分别是什 么字母。统计出各个字母在字符串中分别出现了多少次,找到出现次数多的。这里要注意 三点:
(1) 输入字符串时,可以象一般变量一样,一次输入一个字符串。scanf 函数通过空格或 者回车字符判断一个字符串的结束。而一般数组在输入时,每次只能输入一个数组元 素。
(2) 字符串是一个字符型数组,可以象访问一般数组的元素一样,通过下标访问其中的各 个元素。scanf 函数输入字符串时,并不返回所输入字符串的长度。可以使用字符串 处理函数 strlen 函数计算字符串中包括多少个字符。
(3) 输入的字符串中,可能有多个字符出现的次数相同且多的情况。此时要输出 ascii 码 小的那一个字符。

解决方案
用一个二维数组 telNumbers[100000][9]来存储全部的电话号码,每一行存储一个电话号码 的标准表示。每读入一个电话号码,首先将其转换成标准表示,然后存储到二维数组 telNumbers 中。全部电话号码都输入完毕后,将数组 telNumbers 作为一个一维数组,其中 每个元素是一个字符串,用C/C++提供的函数模板sort对进行排序。用字符串比较函数strcmp 比较 telNumbers 中相邻的电话号码,判断是否有重复的电话号码、并计算重复的次数。

#include <stdio.h>#include <stdlib.h>#include <string.h>char map[] = "22233344455566677778889999";char str[80], telNumbers[100000][9];int compare(const void *elem1,const void *elem2){    return (strcmp((char*)elem1, (char*)elem2));//为函数模板 sort 定义数组元素的比较函数 };void standardizeTel(int n){    int j, k;    j = k = -1 ;    while ( k<8 )    {        j++;        if ( str[j] == '-' )        continue;        k++;        if (k==3)        {            telNumbers[n][k]='-';            k ++;        }        if(str[j]>='A' && str[j]<='Z')        {            telNumbers[n][k]=map[str[j]-'A'];            continue;        }        telNumbers[n][k]=str[j];    }    telNumbers[n][k]='\0';    return;}int main(){    int n,i,j;    bool noduplicate;    scanf("%d",&n);    for(i=0;i<n;i++)//输入电话号码,存储到数组 telNumbers 中     {        scanf("%s",str);        standardizeTel(i);//将 str 中的电话号码转换成标准形式,存储在 telNumbers 的第 i 行     }    qsort(telNumbers,n,9,compare);//对输入的电话号码进行排序     noduplicate = true;    i=0;    while(i<n)    {//搜索重复的电话号码,并进行输出         j=i;        i++;        while(i<n&&strcmp(telNumbers[i], telNumbers[j])==0) i++;        if(i-j>1)        {            printf("%s %d\n", telNumbers[j], i-j);            noduplicate = false;        }    }    if ( noduplicate )printf("No duplicates.\n");    return 0;}

下面用STL工具做的也可以过:

#include<cstdio>#include<iostream>#include<cstring>#include<map>#include<set>using namespace std;map<string,int>phone;set<string>numphone;char a[]="22233344455566677778889999";char s1[10];void number(char *s){    int j=0;    for(int i=0;i<strlen(s);i++)    {        if(j==3)s1[j++]='-';        if(s[i]>='0'&&s[i]<='9')s1[j++]=s[i];        else if(s[i]=='-')continue;        else s1[j++]=a[s[i]-'A'];    }    s1[j]=0;}int main(){    int n;    cin>>n;    while( n-- )    {        memset(s1,0,sizeof(s1));        char s[80];        scanf("%s",s);        number(s);        numphone.insert(s1);        if(phone.count(s1))phone[s1]++;        else phone[s1]=1;    }    int x=0;    for(set<string>::iterator it=numphone.begin();it!=numphone.end();++it)    {        if(phone[*it]!=1){x=1;break;}    }    if(x)    for(set<string>::iterator it=numphone.begin();it!=numphone.end();++it)    {        if(phone[*it]!=1)        cout<<*it<<" "<<phone[*it]<<endl;    }    else cout<<"No duplicates."<<endl;    phone.clear();    numphone.clear();    return 0;}

3.百练2744:子串

问题描述

有一些由英文字符组成的大小写敏感的字符串。请写一个程序,找到一个长的字符串 x, 使得:对于已经给出的字符串中的任意一个 y,x 或者是 y 的子串、或者 x 中的字符反序之后得到的新字符串是 y 的子串。

题目链接
http://bailian.openjudge.cn/practice/2744

解决方案
每输入一组字符串后,首先找到其中短的字符串 x0。然后根据 x0搜索满足条件的子字 符串。对 x0 的各子字符串从长到短依次判断是否满足条件,直到找到一个符合条件的子字 符串为止。
(1) 搜索到 x0的每个子字符串,并且根据子字符串的长度从长到短开始判断,不要遗漏了任 何子字符串。
(2) 熟练掌握下列几个字符串处理函数,确保程序代码简洁、高效。
strlen:计算字符串的长度
strncpy:复制字符串的子串
strcpy:复制字符串
strstr:在字符串中寻找子字符串
strrev:对字符串进行反序
注:在用 strncpy 取子串时,需要在所取子串的末尾添加字符串结束符’\0’。

#include<string.h>#include<cstdio>#include<iostream>using namespace std;char* strrev(char* s){    char* h = s;    char* t = s;    char ch;    while(*t++){};    t--;        t--;       while(h < t)    {        ch = *h;        *h++ = *t;            *t-- = ch;        }    return(s);}int main(){    int n;    char s[110][110];    char minstr[110],sub[110],revsub[110];    cin>>n;getchar();    while(n--)    {        int t,minlen=1000;        memset(s,0,sizeof(s));        memset(minstr,0,sizeof(minstr));        cin>>t;        for(int i=1;i<=t;i++)        {        getchar();            scanf("%s",&s[i]);            if(minlen>strlen(s[i]))            {                strcpy(minstr,s[i]);                minlen=strlen(s[i]);            }        }        bool x;        while(minlen)        {            for(int i=0;i<=strlen(minstr)-minlen;i++)            {                strncpy(sub,minstr+i,minlen);                strncpy(revsub,minstr+i,minlen);                sub[minlen]=revsub[minlen]='\0';                strrev(revsub);                x=true;                for(int j=1;j<=t;j++)                {                    if(strstr(s[j],sub)==NULL&&strstr(s[j],revsub)==NULL)                    {                        x=false;                        break;                    }                }                if(x)break;            }if(x)break;            minlen--;        }        printf("%d\n",minlen);    }    return 0;}

4.2975:Caesar 密码

问题描述
Julius Caesar 生活在充满危险和阴谋的年代。为了生存,他首次发明了密码,用于军队的 消息传递。假设你是 Caesar 军团中的一名军官,需要把 Caesar 发送的消息破译出来、并提 供给你的将军。
消息加密的办法是:对消息原文中的每个字母,分别用该字母之后的第 5 个字母替换(例如:消息原文中的每个字母 A 都分别替换成字母 F),其他字符不 变,并且 消息原文的所有字母都是大写的。
密码中的字母与原文中的字母对应关系如下。
密码字母:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
原文字母:V W X Y Z A B C D E F G H I J K L M N O P Q R S T U

题目链接
http://bailian.openjudge.cn/practice/2975

问题分析
此问题非常简单,将密码消息中的每个字母分别进行相应的变换即可。
关键是识别输入数 据中的消息行、读入消息行的数据。输入数据中,每个消息行包括多个单词、以及若干个标 点符号。
(1) scanf 函数输入字符串时,每个字符串中不能有空格。每读到单词”START”,则表示下面 读到的是一个消息行中的单词,直到读到单词”END”为止。
(2) 对消息解密时,需要将表示消息中单词的字符串作为普通的数组,依次变换其中的每个 字母。

解决方案
读到消息行之后,通过 scanf 读如其中的每个单词,分别解密。将解密后的单词按照原来 的顺序,拼接成一条完整的消息。
需要用到下列几个字符串处理函数:
strcmp:识别输入数据中消息行的开始和结束
strlen:计算加密消息中每个单词的长度
strcat:将解密后的单词重新拼接成一条完整的消息

#include<cstdio>#include<cstring>char c[]="VWXYZABCDEFGHIJKLMNOPQRSTU";int main(){    char s[101];    int i;    while(1)    {        gets(s);        if(strcmp(s,"ENDOFINPUT")==0)break;        gets(s);        for(i=0;i<strlen(s);i++)        {            if(s[i]>='A'&&s[i]<='Z')printf("%c",c[s[i]-'A']);            else printf("%c",s[i]);        }        printf("\n");        gets(s);    }    return 0;}

5.2743:字符串判等

问题描述
给定两个由大小写字母和空格组成的字符串 s1和 s2,它们的长度都不超过 100 个字符、 也可以长度为 0。判断压缩掉空格、并忽略大小写后,这两个字符串在是否相等。

题目链接
http://bailian.openjudge.cn/practice/2743

#include<cstdio>#include<cstring>void f(char*c){    int j=0;    for(int i=0;i<strlen(c);i++)    {        if(c[i]==' ')continue;        if(c[i]>='A'&&c[i]<='Z')c[j++]=c[i]+32;        else c[j++]=c[i];    }    c[j]='\0';}int main(){    char s1[110],s2[110];    gets(s1);    gets(s2);    f(s1);    f(s2);    if(strcmp(s1,s2)==0)printf("YES\n");    else printf("NO\n");    return 0;}

6.1936:全在其中

题目描述
你设计了一个新的加密技术,可以用一种聪明的方式在一个字符串的字符间插入随机的字符串从而对信息进行编码。由于专利问题,我们将不会详细讨论如何在原有信息中产生和插入字符串。不过,为了验证你的方法,有必要写一个程序来验证原来的信息是否全在最后的字符串之中。
给定两个字符串s和t,你需要判断s是否是t的“子列”。也就是说,如果你去掉t中的某些字符,剩下字符将连接而成为s。

题目链接
http://bailian.openjudge.cn/practice/1936

#include<cstring>#include<iostream>#include<cstdio>using namespace std;char s[100000],t[100000];int main(){    while(scanf("%s%s",s,t)!=EOF)    {        int len1=strlen(s);        int len2=strlen(t);        int i,j,num=0;        for(i=0,j=0;i<len1&&j<len2;j++)        {            if(s[i]==t[j]){num++;i++;}        }        if(num>=strlen(s))cout<<"Yes"<<endl;        else cout<<"No"<<endl;    }    return 0;}

此处输入输出流较大,用C语言中的输入输出更快,用c++的cin和cout容易超时,而且要直接定义len1=strlen(s);len2=strlen(t);一开始我没有直接定义,是直接把它放到了循环的判断条件中,这样每一次循环都要调用一次,使得速度慢了下来,直接超时。

7.2818:密码

题目描述
Bob 和 Alice 开始使用一种全新的编码系统。它是一种基于一组私有钥匙的。他们选择了n个不同的数a1 , …,an, 它们都大于0小于等于n。 机密过程如下:待加密的信息放置在这组加密钥匙下,信息中的字符和密钥中的数字一一对应起来。信息中位于i位置的字母将被写到加密信息的第ai个位置, ai 是位于i位置的密钥。加密信息如此反复加密,一共加密 k 次。
信息长度小于等于n。如果信息比 n 短, 后面的位置用空格填补直到信息长度为n。
请你帮助 Alice 和 Bob 写一个程序,读入密钥,然后读入加密次数 k 和要加密的信息,按加密规则将信息加密。

题目链接
http://bailian.openjudge.cn/practice/2818

#include<stdio.h>#include<string.h>int main (){    int n,k,i,j,t,a[201],con[201];    char str[201],str1[201];    while(scanf("%d",&n)&&n)    {        for(i=1;i<=n;i++)scanf("%d",&a[i]);        memset(con,0,sizeof(con));        for(i=1;i<=n;i++)        {            int t=a[i];            while(1)            {                con[i]++;                if(t==i)break;                else t=a[t];            }        }        while(scanf("%d",&k)&&k)        {            getchar();            gets(str);            if(strlen(str)<n)for(i=strlen(str);i<n;i++)str[i]=' ';            str[i]='\0';            for(i=0;i<n;i++)            {                t=i+1;                for(j=0;j<(k%con[i+1]);j++)t=a[t];                str1[t-1]=str[i];            }            str1[n]='\0';            printf("%s\n",str1);        }        printf("\n");    }    return 0;}

8.2819:W的密码

题目描述
加密一条信息需要三个整数码, k1, k2 和 k3。字符[a-i] 组成一组, [j-r] 是第二组, 其它所有字符 ([s-z] 和下划线)组成第三组。 在信息中属于每组的字符将被循环地向左移动ki个位置。 每组中的字符只在自己组中的字符构成的串中移动。解密的过程就是每组中的字符在自己所在的组中循环地向右移动ki个位置。
例如对于信息 the_quick_brown_fox 以ki 分别为 2, 3 和 1蔼进行加密。加密后变成 _icuo_bfnwhoq_kxert。

题目链接
http://bailian.openjudge.cn/practice/2819

#include<iostream>#include<cstring>#include<cstdio>using namespace std;void f(char*a,int k,int x){    for(int i=0;i<k;i++)    {        int t=a[x];        for(int j=x;j>1;j--)        {            a[j]=a[j-1];        }        a[1]=t;    }}int main(){    int k1,k2,k3,x[100],num[100];    char str[100],a[100],b[100],c[100];    while(cin>>k1>>k2>>k3)    {        if(k1==0&&k2==0&&k3==0)break;        memset(str,0,sizeof(str));        memset(x,0,sizeof(x));        memset(a,0,sizeof(a));        memset(b,0,sizeof(b));        memset(c,0,sizeof(c));        memset(num,0,sizeof(num));        int i,ii,jj,kk;        ii=jj=kk=0;        getchar();        for(i=0;;i++)        {            scanf("%c",&str[i]);            if(str[i]=='\n')break;            if(str[i]>='a'&&str[i]<='i'){a[++ii]=str[i];num[i]=1;}            if(str[i]>='j'&&str[i]<='r'){b[++jj]=str[i];num[i]=2;}            if(str[i]>='s'&&str[i]<='z'||str[i]=='_')            {                c[++kk]=str[i];num[i]=3;            }        }        f(a,k1,ii);        f(b,k2,jj);        f(c,k3,kk);        int len=strlen(str);        ii=jj=kk=0;        for(i=0;i<len;i++)        {            switch(num[i])            {                case 1:cout<<a[++ii];                break;                case 2:cout<<b[++jj];                break;                case 3:cout<<c[++kk];            }        }        cout<<endl;    }    return 0;}

9.2820:古代密码

题目描述
古罗马帝国有一个拥有各种部门的强大政府组织。其中一个部门就是保密服务部门。为了保险起见,在省与省之间传递的重要文件中的大写字母是加密的。当时最流行的加密方法是替换和重新排列。
替换方法是将所有出现的字符替换成其它的字符。有些字符会替换成它自己。例如:替换规则可以是将’A’ 到 ‘Y’替换成它的下一个字符,将’Z’替换成 ‘A’,如果原词是 “VICTORIOUS” 则它变成 “WJDUPSJPVT”。
排列方法改变原来单词中字母的顺序。例如:将顺序<2, 8=”“>应用到 “VICTORIOUS” 上,则得到”IVOTCIRSUO”。
人们很快意识到单独应用替换方法或排列方法加密,都是很不保险的。但是如果结合这两种方法,在当时就可以得到非常可靠的加密方法。所以,很多重要信息先使用替换方法加密,再将加密的结果用排列的方法加密。用两种方法结合就可以将”VICTORIOUS” 加密成”JWPUDJSTVP”。
考古学家最近在一个石台上发现了一些信息。初看起来它们毫无意义,所以有人设想它们可能是用替换和排列的方法被加密了。人们试着解读了石台上的密码,现在他们想检查解读的是否正确。他们需要一个计算机程序来验证,你的任务就是写这个验证程序。

题目链接
http://bailian.openjudge.cn/practice/2820

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int main(){    int i,a[30],b[30];    char s[110],t[110];    memset(a,0,sizeof(a));    memset(b,0,sizeof(b));    scanf("%s%s",s,t);    for(i=0;i<strlen(s);i++)a[s[i]-'A']++;    for(i=0;i<strlen(t);i++)b[t[i]-'A']++;    sort(a,a+26);    sort(b,b+26);    for(i=0;i<26;i++)    {        if(a[i]!=b[i])break;    }    if(i==26)printf("YES\n");    else printf("NO\n");    return 0;}

10.2804:词典

题目描述
你旅游到了一个国外的城市。那里的人们说的外国语言你不能理解。不过幸运的是,你有一本词典可以帮助你。
首先输入一个词典,词典中包含不超过100000个词条,每个词条占据一行。每一个词条包括一个英文单词和一个外语单词,两个单词之间用一个空格隔开。而且在词典中不会有某个外语单词出现超过两次。词典之后是一个空行,然后给出一个由外语单词组成的文档,文档不超过100000行,而且每行只包括一个外语单词。输入中出现单词只包括小写字母,而且长度不会超过10。
在输出中,你需要把输入文档翻译成英文,每行输出一个英文单词。如果某个外语单词不在词典中,就把这个单词翻译成“eh”。

题目链接
http://bailian.openjudge.cn/practice/2804

#include<cstdio>#include<string>#include<cstring>#include<map>#include<algorithm>#include<iostream>using namespace std;map<string,string>word;int main(){    string x,y;    char str[30],a[15],b[15];    while(fgets(str,29,stdin),str[0]!='\n')    {        sscanf(str,"%s%s",a,b);        x=a;y=b;        word[y]=x;        x.clear();y.clear();        memset(a,0,sizeof(a));        memset(b,0,sizeof(b));    }    memset(a,0,sizeof(a));    x.clear();    while(scanf("%s",a)!=EOF)    {        x=a;        if(word.count(x))cout<<word[x]<<endl;        else printf("eh\n");        x.clear();        memset(a,0,sizeof(a));    }    return 0;}

网上大多使用sort和函数模板bsearch,自我感觉用STL写起来简单。

11.2797:最短前缀

题目描述
一个字符串的前缀是从该字符串的第一个字符起始的一个子串。例如 “carbon”的字串是: “c”, “ca”, “car”, “carb”, “carbo”, 和 “carbon”。注意到这里我们不认为空串是字串, 但是每个非空串是它自身的字串. 我们现在希望能用前缀来缩略的表示单词。例如, “carbohydrate” 通常用”carb”来缩略表示. 现在给你一组单词, 要求你找到唯一标识每个单词的最短前缀
在下面的例子中,”carbohydrate” 能被缩略成”carboh”, 但是不能被缩略成”carbo” (或其余更短的前缀) 因为已经有一个单词用”carbo”开始
一个精确匹配会覆盖一个前缀匹配,例如,前缀”car”精确匹配单词”car”. 因此 “car” 是 “car”的缩略语是没有二义性的 , “car”不会被当成”carriage”或者任何在列表中以”car”开始的单词.

题目链接
http://bailian.openjudge.cn/practice/2797

#include<cstdio>#include<cstring>#include<iostream>using namespace std;char word[1010][25];int main(){    int counts=0,i,j,k;    char a[25],b[25];    while(scanf("%s",word[counts])!=EOF)counts++;    for(i=0;i<counts;i++)    {        int len=strlen(word[i]);        for(j=1;j<len;j++)        {            strcpy(a,word[i]);            a[j]='\0';            for(k=0;k<counts;k++)            {                //if(k==i)continue;                strcpy(b,word[k]);                b[j]='\0';                if(!strcmp(a,b)&&k!=i)break;            }            if(k>=counts)break;        }        if(j==len)printf("%s %s\n",word[i],word[i]);        else printf("%s %s\n",word[i],a);    }    return 0;}

12.2799:浮点数格式

题目描述
输入n个浮点数,要求把这n个浮点数重新排列后再输出
(这里是重新排列,不是排序,排列规则详见题目)

题目链接
http://bailian.openjudge.cn/practice/2799

#include<stdio.h>#include<string.h>char str[10010][55];int len[10010];int main(){    int n;    memset(len,0,sizeof(len));    scanf("%d",&n);    for(int i=0;i<n;i++){        scanf("%s",str[i]);        for(int j=0;str[i][j]!='.';j++){            len[i]++;        }    }    int max=len[0];    for(int i=1;i<n;i++){        if(max<len[i]) max=len[i];    }    for(int i=0;i<n;i++){        for(int j=0;j<max-len[i];j++){            printf(" ");        }        printf("%s\n",str[i]);    }}
1 0
原创粉丝点击