題目:輸入兩個字符串,從第一字符串中刪除第二個字符串中所有的字符。例如,輸入”They are students.”和”aeiou”,則刪除之后的第一個字符串變成”Thy r stdnts.”。
這道題的基本思路就是在第一個字符串中拿到一個字符,在第二個字符串中查找一下,看它是不是在第二個字符串中。如果在的話,就從第一個字符串中刪除。
首先我們考慮如何在字符串中刪除一個字符。由於字符串的內存分配方式是連續分配的。我們從字符串當中刪除一個字符,需要把后面所有的字符往前移動一個字節的位置。但如果每次刪除都需要移動字符串后面的字符的話,對於一個長度為n的字符串而言,刪除一個字符的時間復雜度為O(n)。而對於本題而言,有可能要刪除的字符的個數是n,因此該方法就刪除而言的時間復雜度為O(n2)。
事實上,我們並不需要在每次刪除一個字符的時候都去移動后面所有的字符。我們可以設想,當一個字符需要被刪除的時候,我們把它所占的位置讓它后面的字符來填補,也就相當於這個字符被刪除了。在具體實現中,我們可以定義兩個指針(pFast和pSlow),初始的時候都指向第一字符的起始位置。當pFast指向的字符是需要刪除的字符,則pFast直接跳過,指向下一個字符。如果pFast指向的字符是不需要刪除的字符,那么把pFast指向的字符賦值給pSlow指向的字符,並且pFast和pStart同時向后移動指向下一個字符。這樣,前面被pFast跳過的字符相當於被刪除了。用這種方法,整個刪除在O(n)時間內就可以完成。
接下來我們考慮如何在一個字符串中查找一個字符。當然,最簡單的辦法就是從頭到尾掃描整個字符串。顯然,這種方法需要一個循環,對於一個長度為n的字符串,時間復雜度是O(n)。
由於字符的總數是有限的。對於八位的char型字符而言,總共只有28=256個字符。我們可以新建一個大小為256的數組,把所有元素都初始化為0。然后對於字符串中每一個字符,把它的ASCII碼映射成索引,把數組中該索引對應的元素設為1。這個時候,要查找一個字符就變得很快了:根據這個字符的ASCII碼,在數組中對應的下標找到該元素,如果為0,表示字符串中沒有該字符,否則字符串中包含該字符。此時,查找一個字符的時間復雜度是O(1)。其實,這個數組就是一個hash表。
#include <iostream>
using namespace std;
void DeleteChars(char *first,char *second)
{
if(first==NULL||second==NULL)
return;
//hashTable標記字符是否在字符串second中出現...
bool hashTable[256];
memset(hashTable,0,sizeof(hashTable));
size_t len1=strlen(first);
size_t len2=strlen(second);
//掃描字符串second,在hashTable中標記出現的字符
for(int i=0;i<len2;i++)
if(!hashTable[second[i]])
hashTable[second[i]]=true;
char *fast=first;
char *slow=first;
//刪除first中出現在second中的字符
while(*fast!='\0')
{
if(!hashTable[*fast])
{
*slow=*fast;
++slow;
}
++fast;
}
*slow='\0';
}
int main()
{
char first[]="They are students";
char second[]="aeiou";
DeleteChars(first,second);
cout<<first<<endl;
system("pause");
return 0;
}