2005年百度之星预赛第三题

 

     题目描述:请编写程序,根据指定的对应关系,把一个文本中的字符串替换成另外的字符串。

输入数据:程序读入已被命名为 text.txt dict.txt 的两个输入数据文本文件, text.txt 为一个包含大量字符串(含中文)的文本,以 whitespace 为分隔符; dict.txt 为表示字符串( s1 )与字符串( s2 )的对应关系的另一个文本(含中文),大约在 1 万行左右,每行两个字符串(即 s1 s2 ),用一个 /t 或空格分隔。 dict.txt 中各行的 s1 没有排序,并有可能有重复,这时以最后出现的那次 s1 所对应的 s2 为准。 text.txt dict.txt 中的每个字符串都可能包含除 whitespace 之外的任何字符。 text.txt 中的字符串必须和 dict.txt 中的某 s1 完全匹配才能被替换。(为便于调试,您可下载测试 text.txt dict.txt 文件,实际运行时我们会使用不同内容的输入文件。)

     输出数据:在标准输出上打印 text.txt dict.txt 替换后了的整个文本。

     评分标准:程序输出结果必须正确,内存使用越少越好,程序的执行时间越快越好。

     关于这道题的一些想法,最直接的做法是读入字典,然后比较字符串是否出现过,没有出现过加入替换的字符串,出现过了则替换。可以考虑使用映射,使用STL里面的Map。然后读入text.txt字符串,找到Map的字符串,如果存在替换输出,没有的话,输出本身。

复杂度分析:构建字典的去重需要On^2),n为单词个数。然后替换需要时间为o(n*m)mtext.txt文本中单词的个数。而且里面会大量使用字符串比较函数strcmp

     其实,上面那种想法有点绕弯了,可以不去重的,“以最后出现的那次 s1 所对应的 s2 为准”,那么只要将dict.txt读到一个list里面,然后从List后面往前面比较,如果相同替换,不同打印本身。复杂度为On*m)。

     这种方法我没有去实现。有兴趣的同学可以试试。

     另外一种思路,其实这道题归根结底就是字符串比较的问题,text.txt文本中字符串S1,如果和dict.txt中的S2(最后出现的)相同,则替换。则不管S1S2中包含那种字符,中文字符也好,英文字符也好,他们的字节流一定是相同的。(因为C++GB2312编码,中文字符是2字节,英文字符是1字节的,而这中文字符的字节的取值范围是161-255,具体可以参见http://www.cublog.cn/u2/64540/showart_522529.html这里面中文字符的处理方式)。

      那么我们可以构建一棵Trie树,树底下有256(一个字节取值范围为0-255)个节点,用于构建字典树,耗时为O(n)。事实上为on*k),k为字符串长度,上面字符串比较的时候没有考虑k,在这里也就忽略了。那么替换text.txt字符串的复杂度为om),同样忽略了k,速度跟上面那种方法比较应该能够取得很大的进步。代码实现如下:

#include <iostream> #include <fstream> using namespace std; const int CSIZE = 256; const int SIZE = 10000; struct WTree { WTree *next[CSIZE]; int index; }; char repwld[SIZE][CSIZE]; int rwl=0; ifstream dictfin("dict.txt"); ifstream txtfin("text.txt"); ofstream fout("result.txt"); //构建Trie字典树 WTree tree; void read_dict() { char w[CSIZE]; char r[CSIZE]; while (!dictfin.eof()) { dictfin >> w >> r; //构建Trie树 int wl = strlen(w); WTree * temp = &tree; for (int i=0; i < wl; i ++) { int idx = w[i]; if (temp->next[idx] == NULL) { temp->next[idx] = new WTree(); temp = temp->next[idx]; temp->index = -1; } else { temp = temp->next[idx]; }//end else } //找到位置放进替代的单词 int ridx = 0; if(temp->index == -1) { ridx = rwl; temp->index = ridx; rwl ++; } else ridx = temp->index; int rl = strlen(r); int i=0; for (i=0; i < rl; i++) { repwld[ridx][i] = r[i]; } repwld[ridx][i] = '/0'; }//end while } void replace() { char w[CSIZE]; while (!txtfin.eof()) { txtfin >> w; int wl = strlen(w); WTree * tmp = &tree; bool flag = false; for (int i=0; i < wl; i ++) { int idx = w[i]; if (tmp->next[idx] == NULL) { flag = false; break; }//end if tmp else { flag = true; tmp = tmp->next[idx]; }//end else }//end for i if (flag&&tmp->index != -1) { fout << repwld[tmp->index]<<endl; } else fout << w << endl; } } int main() { read_dict(); replace(); return 0; } 

     百度之星05年第4题,我觉得同样可以考虑使用Trie树来实现,一遍构造,终生幸福。

 

你可能感兴趣的:(2005年百度之星预赛第三题)