這是近幾天在LintCode上遇到的一道題,題目如下:
比較兩個字符串A和B,確定A中是否包含B中所有的字符。字符串A和B中的字符都是大寫字母:
給出 A = "ABCD" B = "AABC", 返回 false
給出 A = "ABCD" B = "ACD",返回 true
- 一開始的思路是用A的每一位去和B的每一位去比較。
如果說B每一位都能在A中找到的話,則A中包含B。
代碼如下:
bool compareStrings(string A, string B) {
int countA = A.length();
int countB = B.length();
int sub = 0;
int temp[countB];
for (int i = 0; i < countB; i++) {
temp[i]=0;
}
for (int i = 0; i < countA; i++) {
for (int n = 0; n < countB; n++) {
if ( A[i] == B[n]) {
temp[n] = 1;
}
}
}
for (int i = 0; i < countB; i++) {
sub = temp[i] + sub;
}
if (sub == countB)
return true;
else
return false;
}
但是在遇到B的字符里有A的重復個的時候:
"ABCDEFG", "ACC"
A的同一個C會在B中判斷兩次,導致輸出的結果為true,但其實應該為false。
-
所以這次改進代碼,避免一個字符的多次判定。
要做的很簡單,在判定存在的語句后面加上一個break。for (int i = 0; i < countA; i++) { for (int n = 0; n < countB; n++) { if ( A[i] == B[n]) { temp[n] = 1; break; } } }
就像上面提到的情況,問題又出現了:
"AAAAAAAAAAAABBBBBCDD", "ABCDD"(true)
A的DD在B中只判定了B的第一個D,就跳出了,所以輸出為false。
-
……很無奈接著補充代碼:
for (int i = 0; i < countA; i++) { for (int n = 0; n < countB; n++) { if ( A[i] == B[n]) { temp[n] = 1; if ( A[i] != A[i-1])//當A的后一個字符與前一個不一樣時才跳出循環 break; } } }
好吧,糟糕的情況又出現了。
"AAAAAAAAAAAAAAAAAAABBBBBBBBBDFADSFJALSDJFALSDJFSADFADF", "AAAAAABBBBBBBBBDFJALDJF"(true)
這里又錯誤的返回了一個fasle,由于A中的D并不是連續,所以和上面的錯誤類似,B中的第二個D不能得到判定。
做到這里就不得不說下了,像你已經看到這種修修補補的代碼,一般情況下都是很糟糕的,而且問題較多。因為必須要順著前面的思路,來解決后面的問題 ,你很有可能發現之前的算法結構在解決后面出現問題時是異常困難的。最好構造算法之前就要考慮到最壞的情況,或者說最后重構下自己的代碼。
由于我一開始看到題目中給的的數據很簡單就沒考慮到現在的情況。
我覺得我的方法需要換一種了。
思路如下:
- 統計兩邊的信息進行比較。如果B中的每種字符的個數小于等于A中的,則A包含B。
代碼如下:
int Achar[26];//儲存字符串的每個字母個數
int Bchar[26];
for (int i = 0; i<26; i++) {
Achar[i] = 0;
Bchar[i] = 0;
}
int Adate,Bdate;//記錄AB的字符統計數據
int countA = A.length();
int countB = B.length();
for (int i = 0; i<countA; i++) {
int index;
index = A[i] - 65;
Achar[index]++;
}
for (int i = 0; i<countB; i++) {
int index;
index = B[i] - 65;//65為大寫A的ASCⅡ碼值
Bchar[index]++;
}
for (int i = 0; i<26; i++) {
if (Achar[i]<Bchar[i])
return false;
}
return true;
}
這一次19個測試數據全部通過。??