字符串

前述

首先介绍一些技巧总结:
1) scanf与gets的区别:scanf读取到空格或换行,gets读取到换行。
2) 需要保存最后输出字符串的时候可以自定义数组char ch[max]来保存,记得加串尾。
3) string.h里面一些常用的函数memcpy,strcpy,strcmp,strchr,strstr,strlen, strtok。
ctype.h里面一些常用函数isalnum, isalpha, isdigit, islower/isupper, tolower/toupper。

现在再谈谈POJ上面的一些处理字符串类型的题目

POJ1598

题目描述:给你K个小写字母组成的单词,E个句子,先要你输出包含K个单词中的单词数目最多的句子,如有多个这样的句子,不要求顺序的输出。句子匹配不考虑大小写。
解题思路:网上可能有些其他的思路比如STL,排序之类的,这里我采用字符处理提取单词的方法,然后进行匹配计数,最后输出等于最大计数的句子。
源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char pattern[205][205];
char inStr[205][205];
int cnt[205];
int main()
{
int k,e,set=1;
while (scanf("%d%d",&k,&e)==2)
{
memset(cnt,0,sizeof(cnt));
int i,j,m,max=0;
for (i=0;i<k;i++)
scanf("%s",&pattern[i]);
getchar();
for (i=0;i<e;i++)
{
gets(inStr[i]);
int len=strlen(inStr[i]);
char ch[105];
for (j=0;j<len;j++)
{
int a=0;
while (isalpha(inStr[i][j]))
{
ch[a++] = tolower(inStr[i][j]);
j++;
}
if (a>0)
{
ch[a]='\0';
for (m=0;m<k;m++)
if (strcmp(ch,pattern[m])==0)
{
cnt[i]++;
break;
}
}
}

}
for (i=0;i<e;i++)
{
if (cnt[i] > max)
{
max = cnt[i];
}
}
printf("Excuse Set #%d\n",set++);
for (i=0;i<e;i++)
{
if (max==cnt[i])
printf("%s\n",inStr[i]);
}
printf("\n");
}
return 0;
}

POJ1782

题目描述:题意不容易理解,主要是需要你重新编码。规则如下:
1)将连续相同的字符串依次输出个数,字符,如果个数大于9就需要重新使用编码规则
2)将不相同的字符串首尾各添加1,在不相同的字符串中如果出现1就将其转换成2个1
解题思路:每次记录上一个字符与当前字符比较,如果相等将计数+1,如果计数达到8就可以输出并且将计数清0,为什么我这里处理是8,因为个数等于9需要比较8次。如果不相等就一直循环到相等的时候退出,在此过程中需要保存不相同的字符串,如果遇到1就保存2个1,最后还需要在前面和后面都添加1,到字符相等的时候就输出。
源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <stdio.h>
#include <string.h>

#define N 10000+5

char str[N];

int main()
{
while(NULL != gets(str))
{
int i,len = strlen(str),cnt=0;
char c = str[0];
for (i=1;i<=len;i++){
if (cnt==8){
printf("%d%c",cnt+1,c);
cnt=0;
c=str[i];
}
else if (c == str[i])
cnt++;
else
{
if (cnt>0&&cnt<9){
printf("%d%c",cnt+1,c);
cnt=0;
c=str[i];
}else{
char ch[N];
int j=0;
ch[j++]='1';
while (1)
{
if (str[i]==c||i>=len)
{
if (i==len)
{
if (str[i-1]=='1'){
ch[j++]='1';
ch[j++]='1';
}else{
ch[j++]=str[i-1];
}
}
ch[j++]='1';
ch[j]='\0';
printf("%s",ch);
if (i!=len)
cnt++;
break;
}
if (str[i-1]=='1'){
ch[j++]='1';
ch[j++]='1';
}else{
ch[j++]=str[i-1];
}
c=str[i];
i++;
}
}
}
}
printf("\n");
}
return 0;
}

POJ1936

题目描述:给你两个字符串s和t,判断s是否是t的子串。这里的子串之意就是s字符串中每个字符的先后顺序在t中的顺序也应该一样。
解题思路:此题应该很容易想到字符比较,如果si==ti则都往后推1,否则t往后推。
源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <string.h>
#define N 100000+5
char s[N],t[N];

int main()
{
while (scanf("%s%s",&s,&t)==2){
int lens=strlen(s),lent=strlen(t);
int i=0,j=0;
bool flag=false;
while (i<lens&&j<lent)
{
if (s[i]==t[j]){
i++;
j++;
}
else
j++;
}
if (i==lens)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}

POJ1790

题目描述:给你一串数字s,分成权数和基数,要求权数小于基数。求解有多少种分法?比如1234可以分成
(1-2-3)4, (1-2)34, (12)34, (1)234。
解题思路:类似于动态规划的思想,分别处理基数长度为1~数字串长度-1,然后将所有的种数相加,那么怎么比较?使用strncmp()函数。cnt[i]表示以s+i起始的基数总共有多少种分法。cnt[i]应该加上所有以len-i为基数的cnt。
源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <string.h>

char s[100+5];
int cnt[100+5];
int len;

int num(int cur)
{
if (s[len-cur]=='0')
return 0;
int i;
cnt[0]=1;
for (i=1;i<=len-cur;i++)
{
cnt[i]=0;
int minn;
if (i-cur<0)
minn=0;
else
minn=i-cur;
for (int j=minn; j<i; j++){
if ((j+1<i || j==0 && len-cur>1) && s[j]=='0') continue;
if (j+cur==i) if (strncmp(s+j,s+len-cur,cur)>=0) continue;
cnt[i]+=cnt[j];
}
}

return cnt[len-cur];
}

int main()
{

while (scanf("%s",&s)==1)
{
if (s[0]=='#')
break;
int ans=0,i;
len = strlen(s);
for (i=1;i<len;i++)
ans+=num(i);
if (ans>0)
printf("The code %s can represent %d numbers.\n",s,ans);
else
printf("The code %s is invalid.\n",s);
}
return 0;
}