問題引入
最近在解決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()函數我將在下一篇博客中詳細介紹。