轉載請註明出處:http://blog.csdn.net/ns_code/article/details/21328151
題目:
Design an algorithm and write code to remove the duplicate characters in a string without using any additional buffer. NOTE: One or two additional variables are fine. An extra copy of the array is not.
FOLLOW UP
Write the test cases for this method.
翻譯:
移除字串中重複的字元,如abcadc移除後變為abcd,可以額外定義一兩個變數,但不允許額外開闢一個數組。並為該演算法寫測試案例。
思路:
本題目主要是限制了空間複雜度,如果沒有這個要求,我們可以有很優的解法(假設字串中的字母都是小寫字母):
比如當字串很長時,我們可以採取同Q1.1題目中相同的思路,開設一個大小為26的bool數組,初始值為false,遍曆字串,第一次遇到某個字元,將該字元在bool數組中對應位置的元素置為true,如果再次遇到,說明出現了重複字元,將該字元移除即可。
再比如,如果字串不是很長,那我們可以考慮採用KMP演算法中的首碼數組,開闢一個比字串長度大1的數組(對最後一個字元'\0'同樣要求其首碼值)來作為該字串的首碼數組,如果首碼數組中的值next[i]>0,則說明該位置前面連續next[i]個位置上的字元與前面的字元重複,可以將這些字元移除。
但是這裡要求了空間複雜度為O(1),那我們只能用最簡單的遍曆方法,先讓第一個字元與後面的字元一一比較,遇到重複的就把重複的字元用'\0'替換掉,再讓第二個字元與右面的字元一一比較,遇到重複的,就把重複的字元用'\0'代替,如此迴圈,直到最後一個字元,當然同時還要在每次遇到'\0'時(重複字元出現的位置,已被填充為'\0'),將後面的字元移到前面來,替換掉'\0',最後將移位後的最後一個位置設為'\0',標誌該字串的結束。時間複雜度為O(n*n)。
測試案例我們需要考慮如下幾種情況:
char str1[] = "abcdfbdk";//隨機字串
char str2[] = "abababab";//重複字元交替出現
char str3[] = "aaaabbbb";//重複字元連續出現
char str4[] = "aaaaaaaa"; //全是重複字元
char str5[] = "abcdefgh"; //沒有重複字元
char str6[] = ""; //Null 字元串
實現代碼:
/***********************************************題目描述:移除字串中重複的字元,如abcadc移除後變為abcd,可以額外定義一兩個變數,但不允許額外開闢一個數組,並為該演算法寫測試案例Date:2014-03-16************************************************/#include<stdio.h>#include<string.h>void remove(char *str){int len = strlen(str);if(len<2)return;int i,j;int p = 0;//p的初值與i相等,均為0for(i=0;i<len;i++){//如果該字元不為'\0',則與下面的字元比較if(str[i]){//如果當前字元不為'\0'時,p一直與i相等,//如果當前字元為'\0',則p會小於i,從而用後面的字元來填充前面'\0'字元的位置str[p++] = str[i];//每個字元與其後面的字元比較,//如果出現重複字元,則將後面的重複字元用'\0'代替for(j=i+1;j<len;j++)if(str[i] == str[j])str[j] = '\0';}}str[p] = '\0';}int main(){char str1[] = "abcdfbdk";//隨機字串char str2[] = "abababab";//重複字元交替出現char str3[] = "aaaabbbb";//重複字元連續出現char str4[] = "aaaaaaaa"; //全是重複字元char str5[] = "abcdefgh"; //沒有重複字元char str6[] = "";//Null 字元串remove(str1);remove(str2);remove(str3);remove(str4);remove(str5);remove(str6);puts(str1);puts(str2);puts(str3);puts(str4);puts(str5);puts(str6);return 0;}
下面再給出一個開闢固定大小的bool數組的方法,也就是我們分析中的第一種方法,實現代碼如下:
/*開闢長為26的bool數組的方法*/void remove1(char *str){int len = strlen(str);if(len < 2)return ;int i;int p = 0;bool A[MAX];memset(A,0,sizeof(A));for(i=0;i<len;i++){int index = str[i] - 'a';if(!A[index]){str[p++] = str[i];A[index] = true;}}str[p] = '\0';}
測試結果: