要求:输入一个主串X和模式串Y,要求删除主串X中在模式串Y中出现的所有字符。如:主串X:welcome to tencent. 模式串Y:aeio。则输出结果为:wlcm t tncnt.
思路:最直接的思路就是用两层for循环,外层for循环扫描主串X,内层for循环用来扫面当前主串X中的字符是否在模式串Y中出现,如果出现则去除该字符,即将从该字符往后到主串末尾全部字符往前移动一位。但这样每次得扫描模式串,我们可以考虑用哈希表存储模式串中出现的字符,即hashTable[*str]==1,然后只需在主串扫描时与哈希表中对应字符的下标中的值比较,若为1则表示应该去除。但这仅仅只降低了扫描模式串的复杂度.
接下来应该考虑减少在主串X中移动当前字符后面字符的次数。我们知道,事实上我们不需要每次删除主串X中某个字符时就移动余下的全部字符,当一个字符需要被删除的时候,我们把它所占的位置让它后面的字符来覆盖,也就相当于删除了这个字符。基于快速排序对冒泡排序改进的思路,我们可以用两个指针first,second,初始时都指向主串的起始位置,然后判断first指向的字符是否需要删除,是则first直接跳过,指向下一个字符。如果first指向的字符是不需要删除的字符,那么把first指向的字符赋值给second指向的字符,然后first和second同时向后移动指向下一个字符,直至first指针到达主串X的末尾。这样时间复杂度降低到了O(n).
基于上述思路代码如下:
#include<iostream> using namespace std; int hashtable[256]; void initTable(char *str) { memset(hashtable,0,sizeof(hashtable)); char *p = str; while(*p!=' ') { hashtable[*p] = 1; p++; } p = NULL; } char *Delete(char *source, char *substr) { char *first = source; char *second = source; while(*first != ' ') { if(hashtable[*first] != 1)//如果主串中的字符在模式串中未出现 { *second = *first; second++; } first++; } *second = ' '; return source; } int main() { int N = 20; char *source = (char *)malloc(sizeof(char)*N); char *substr = (char *)malloc(sizeof(char)*N); cout<<"source string : "; gets(source); cout<<endl<<"substring : "; gets(substr); initTable(substr);//初始化table数组 cout<<Delete(source,substr)<<endl; return 1; }程序运行结果如下: