引入:字符串切割strtok()函数

问题引入

最近在解决AHNU在线测试http://172.16.94.19:8080/JudgeOnline/showproblem?problem_id=1496时,遇到了麻烦,问题描述如下:

Description

读取一行文本,输出相同的文本,但将所有整数中的数字替换成’x’(长度不限)。

Input

一行文本。

Output

替换后的一行文本。

Sample Input

My userID is john17 and my 4 digit pin is 12345 which is secret.

Sample Output

My userID is john17 and my x digit pin is xxxxx which is secret.

初步解决步骤如下:

①将输入的文本text按照空格为分隔符,将每个单词存到字符串数组word中(单词总数可由text字符串中空格数确定);

②对字符串数组word的每一个元素word[i]字符串进行判断,若字符串word[i]中全由数字组成,则将该串的每一个字符替换为'x';

③构造循环,依次输出字符串数组的每一个元素,实现数字替换。

基于以上想法,构造以下函数,分别为:字符串切割函数(实现步骤①)、字符串转换函数(实现步骤②)

字符串切割函数

void Split(char *text,char **word)
{
	int i=0;
	int k=0;//当前已完成单词数
	int j=0;
	while(i<strlen(text))
	{
		j=0;
		while(text[i]!=' '&&text[i]!='\0')
		{
			word[k][j]=text[i];
			j++; 
			i++;
		}
		word[k][j]='\0';
		//printf("%s ",word[k]);
		//printf("k:%d i:%d j:%d\n",k,i,j);
		k++;
		i++;
	}
}

字符串转换函数

void Convert(char **word,int num)//若字符串s中全为数字,则将所有数字转化为'x'
{
	int i,j=0;
	int count=0;
	int R[256]={0}; 
	/*********************初始化数组R**********************/
	for(i=48;i<=58;i++)
	R[i]=1;//数字位置置为1
	 /*****************************************************/
	for(i=0;i<num;i++)
	{
		j=0;
		count=0;
		while(j<strlen(word[i]))
		{
			count+=R[word[i][j]];
			j++;
		}
		//printf("%d ",count);
		if(count==strlen(word[i]))//数字字符数等于字符串长度
		{
			j=0;
			while(j<strlen(word[i]))
			{
				word[i][j]='x';
				j++;
			}
		}
	}
}

主函数

int main()
{
	char text[300000];//要求输入长度无限
	char **word;
	int num=0,i;
	gets(text);
	num=WordCount(text);
	word=(char**)malloc(num*sizeof(char*));
	for(i=0;i<num;i++)
	word[i]=(char*)malloc(50*sizeof(char));//为每个单词分配内存空间
	Split(text,word);
	Convert(word,num);
	for(i=0;i<num;i++)
	printf("%s ",word[i]);//输出测试 
	for(i=0;i<num;i++)
	free(word[i]);//释放每个单词内存空间
	free(word);
	//printf("%d",num);
	return 0;
}

实际运行时,对于长度在可接受范围内的字符串,运行效果良好。但对于测试数据5,输入的数据为一长度近300000的字符串,此时程序运行缓慢,近20s,提交时出现了Time Limit Exceed 的错误。通过分析,主要时间花费在字符串切割函数Split()中,因此若基于以上解题步骤,必须找到一种高效的字符串切割算法。

算法改进

实际上,C语言头文件<string.h>中提供了字符串切割函数strok(),经过测试,该函数的时间复杂度较好,能够满足要求。将其与原字符串切割函数替换后,程序执行时间大大降低,可保持在10s内。Convert()字符串转换函数思想不改,同时将字符串切割体现在主函数里。修改后的Convert()和main()函数如下:

字符串转换函数Convert()

void Convert(char *word)//若字符串s中全为数字,则将所有数字转化为'x'
{
	int i,j=0;
	int count=0;
	int R[256]={0}; 
	/*********************初始化数组R**********************/
	for(i=48;i<=58;i++)
	R[i]=1;//数字位置置为1
	 /*****************************************************/
		j=0;
		count=0;
		while(j<strlen(word))
		{
			count+=R[word[j]];
			j++;
		}
		if(count==strlen(word))//数字字符数等于字符串长度
		{
			j=0;
			while(j<strlen(word))
			{
				word[j]='x';
				j++;
			}
		}
}

主函数main()

int main(void)
{
    char text[3000000];
    gets(text);
    char *temp = strtok(text," ");
    printf("%s\n",temp);
    while(temp)
    {
    	Convert(temp);
        printf("%s ",temp);
        temp = strtok(NULL," ");
    }
    return 0;
}

结论

strotok()函数切割字符串效率较高,实际应用中应当掌握该函数的参数以及返回类型,必要时需要明白实现机制。关于strotok()函数我将在下一篇博客中详细介绍。

猜你喜欢

转载自blog.csdn.net/u012321457/article/details/79595426