【Cracking the Code Interview(5th edition)】一、数组与字符串(C++)
1.1 實現(xiàn)一個算法,確定一個字符串的所有字符是否全都不同。不允許使用額外的數(shù)據(jù)結(jié)構(gòu)。
解答:這里假定字符集為ASCII碼,可以與面試官溝通確認(rèn)字符串使用的字符集。由于字符集是有限的,建立一個數(shù)組模擬的Hash表記錄每個字符是否出現(xiàn),線性掃描一次字符串即可,復(fù)雜度O(len(s)).如果字符集較大,需要考慮空間開銷,則可以用bitset來實現(xiàn)。
1 bool isUnique(string s) { 2 bool record[256]; 3 memset(record, 0, sizeof(record)); 4 size_t size = s.size(); 5 for(size_t i = 0; i < size; ++i) { 6 if (record[s[i]] == true) 7 return false; 8 else 9 record[s[i]] = false; 10 } 11 return true; 12 }可以加一個剪枝:如果字符串的大小大于字符集的大小了,那么該字符串肯定是存在重復(fù)字符的。
1 bool isUnique(string s) { 2 size_t size = s.size(); 3 if (size > 256) 4 return false; 5 bool record[256]; 6 memset(record, 0, sizeof(record)); 7 for(size_t i = 0; i < size; ++i) { 8 if (record[s[i]] == true) 9 return false; 10 else 11 record[s[i]] = false; 12 } 13 return true; 14 }補(bǔ)充:假設(shè)對空間開銷非常嚴(yán)苛,可以考慮先對字符串中的字符排序,然后進(jìn)行一次線性掃描;如果還不允許改變字符串原有的內(nèi)容,那么就只能暴力搜查了吧。
1.2 用C或C++實現(xiàn)void reverse(char * str)函數(shù),即反轉(zhuǎn)一個‘\0’結(jié)尾的字符串。
解答:
1 void reverse(char *str) { 2 if (str == nullptr) return; 3 size_t length = strlen(str); 4 for (size_t i = 0; i < length / 2; ++i) { 5 // swap str[i] and str[length - 1 - i]; 6 char temp = str[i]; 7 str[i] = str[length - 1 - i]; 8 str[length - 1 - i] = temp; 9 } 10 }1.3 給定兩個字符串,請寫程序,確定其中一個字符串的重新排列后,能否變成另一個字符串。
?解答:這里同樣假定字符集是ASCII碼,假定判斷字符串相等時,大小寫是區(qū)分的。在開始時通過檢查兩個字符串長度是否相等進(jìn)行剪枝,然后,用一個數(shù)組記錄第一個字符串中每個字符出現(xiàn)的次數(shù),然后判斷第二個字符串中每個字符出現(xiàn)的次數(shù)是否與第一個字符串相等即可。
1 bool canConvert(string s1, string s2) { 2 if (s1.size() != s2.size()) 3 return false; 4 int record[256]; 5 memset(record, 0, sizeof(record)); 6 for (auto &c : s1) { 7 ++record[c]; 8 } 9 for (auto &c : s2) { 10 if (--record[c] < 0) 11 return false; 12 } 13 return true; 14 }1.4 編寫一個方法,將字符串中的空格全部替換為"%20".假定字符串尾部有足夠的空間存放新增字符,并且知道字符串的真實長度。示例:
輸入: "Mr John Smith"
輸出: "Mr%20John%20Smith"
解答:需要改變字符串長度的問題,通常從尾部開始處理比較高效,因為可以避免字符的重復(fù)移動。
1 void replaceSpace(char str[], int length) { 2 //length為字符串實際長度,不包括結(jié)尾的'\0' 3 if(length <= 0) return; 4 int space_cnt = 0; 5 for (int i = 0; i < length; ++i) { 6 if (str[i] == ' ') { 7 ++space_cnt; 8 } 9 } 10 if (space_cnt > 0) { 11 int j = length + space_cnt * 2; 12 str[j] = '\0'; 13 for (int i = length - 1; i >= 0; --i) { 14 if (str[i] == ' ') { 15 //用"%20"替換空格 16 str[--j] = '0'; 17 str[--j] = '2'; 18 str[--j] = '%'; 19 } else { 20 str[--j] = str[i]; 21 } 22 } 23 } 24 }1.5 利用字符重復(fù)出現(xiàn)的次數(shù),編寫一個方法,實現(xiàn)基本的字符串壓縮功能。比如:字符串"aabbcccccaaa"會變?yōu)?#34;a2b1c5a3".若壓縮后的字符串沒有變短,則返回原先的字符串。
解答:重復(fù)長度編碼(run length encoding, RLE).按照題述模擬即可,但要注意細(xì)節(jié)實現(xiàn)。(其中to_string(int)函數(shù)為C++11新增)
1 string compress(string s) { 2 string ret; 3 int length = s.size(); 4 if (length > 0) { 5 char buf = s[0]; 6 int cnt = 1; 7 for (size_t i = 1; i < length; ++i) { 8 if (s[i] != buf) { 9 ret = ret + buf + to_string(cnt); 10 buf = s[i]; 11 cnt = 1; 12 } 13 else { 14 ++cnt; 15 } 16 } 17 //開始忘記了加這一句,導(dǎo)致最后一組計數(shù)結(jié)果沒有加入ret 18 ret = ret + buf + to_string(cnt); 19 } 20 //注意這里要加等號 21 return ret.size() >= s.size() ? s : ret; 22 }1.6 給定一副NxN矩陣表示的圖像,其中每個圖像的大小為4字節(jié),編寫一個方法,將圖像旋轉(zhuǎn)90°。不占用額外空間能否做到?
解答:常見的問題了,有很多旋轉(zhuǎn)的方式,這里就用最常用的由外向內(nèi)逐層旋轉(zhuǎn)的方法吧。
?這里需要特別注意旋轉(zhuǎn)過程中的循環(huán)停止條件和對應(yīng)的坐標(biāo),不小心非常容易出錯,用含義清晰的變量名有利于理清思路,避免錯誤。
1 void rotate(int **matrix, int n) { 2 for (int layer = 0; layer < n / 2; ++layer) { 3 int last = n - 1 - layer; 4 for (int j = layer; j < last; ++j) { 5 int offset = j - layer; 6 //保存上 7 int temp = matrix[layer][j]; 8 //左->上 9 matrix[layer][j] = matrix[last - offset][layer]; 10 //下->左 11 matrix[last - offset][layer] = matrix[last][last - offset]; 12 //右->下 13 matrix[last][last - offset] = matrix[j][last]; 14 //上->右 15 matrix[j][last] = temp; 16 } 17 } 18 }另外關(guān)于參數(shù)傳遞的問題,這里需要的是一個可變長的二維數(shù)組,C++中我們只能通過傳遞一個二級指針來實現(xiàn),這樣在函數(shù)調(diào)用的時候就需要一些處理了:
1 int main(void) { 2 int arr1[] = { 1, 2, 3, 4 }; 3 int arr2[] = { 5, 6, 7, 8 }; 4 int arr3[] = { 9, 10, 11, 12 }; 5 int arr4[] = { 13, 14, 15, 16 }; 6 int *matrix[4] = { arr1, arr2, arr3, arr4 }; 7 rotate(matrix, 4); 8 return 0; 9 }C++中不能直接給函數(shù)傳遞二維數(shù)組的原因是:“數(shù)組名被改寫成一個指針參數(shù)”規(guī)則并不是遞歸定義的。數(shù)組的數(shù)組會被改寫成“數(shù)組的指針”,而不是“指針的指針”。
?1.7 編寫一個算法,若MxN的矩陣中某個元素為0,則將其所在的行與列都清零。
解答:LeetCode上也有這道題??梢杂靡粋€長度為M的數(shù)組和一個長度為N的數(shù)組分別記錄有0的行和列。此外也可以利用矩陣本身的存儲空間,用其中的一行一列來記錄該結(jié)果。以下代碼基于后一種方法。
1 void setZero(int **matrix, int m, int n) { 2 bool r1_zero = false, c1_zero = false; //兩個變量記錄第一行和第一列是否含0 3 //檢查第一行 4 for (int j = 0; j < n; ++j) { 5 if (matrix[0][j] == 0) { 6 r1_zero = true; 7 break; 8 } 9 } 10 //檢查第一列 11 for (int i = 0; i < m; ++i) { 12 if (matrix[i][0] == 0) { 13 c1_zero = true; 14 break; 15 } 16 } 17 //檢查剩余元素 18 for (int i = 1; i < m; ++i) { 19 for (int j = 1; j < n; ++j) { 20 if (matrix[i][j] == 0) { 21 //將元素是否為0記錄到第一行和第一列 22 matrix[0][j] = matrix[i][0] = 0; 23 } 24 } 25 } 26 //矩陣按規(guī)則置0 27 for (int i = 1; i < m; ++i) { 28 if (matrix[i][0] == 0) { 29 for (int j = 1; j < n; ++j) { 30 matrix[i][j] = 0; 31 } 32 } 33 } 34 for (int j = 1; j < n; ++j) { 35 if (matrix[0][j] == 0) { 36 for (int i = 0; i < m; ++i) { 37 matrix[i][j] = 0; 38 } 39 } 40 } 41 if (r1_zero) { 42 for (int j = 0; j < n; ++j) { 43 matrix[0][j] = 0; 44 } 45 } 46 if (c1_zero) { 47 for (int i = 0; i < m; ++i) { 48 matrix[i][0] = 0; 49 } 50 } 51 }1.8 假定有一個方法isSubstring,可檢查一個單詞是否為其他字符串的子串。給定兩個字符串s1和s2.請編寫代碼檢查s2是否為s1旋轉(zhuǎn)而成,要求只能調(diào)用一次isSubstring.(比如:waterbottle是erbottlewat旋轉(zhuǎn)后的字符串)
解答:s2是s1經(jīng)過一次旋轉(zhuǎn)得到的,那么s1+s1拼成的字符一定把s2包含在其中。可以先判斷兩個字符串的長度是否相等。
1 bool isSubstring(string s1, string s2); //s2是s1的子串是為真 2 3 bool isRotation(string s1, string s2) { 4 if (s1.size() == s2.size() && isSubstring(s1 + s1, s2) { 5 return true; 6 } else { 7 return false; 8 } 9 }補(bǔ)充:第四版中的習(xí)題
1.3 設(shè)計算法并編碼實現(xiàn):在不使用額外緩沖區(qū)的情況下去除字符串中的重復(fù)字符。設(shè)計一些測試用例。
解答:如果允許開辟與字符串長度無關(guān)大小的數(shù)組,則可以用一個記錄字符是否出現(xiàn)過的數(shù)組來實現(xiàn)。
1 void removeDuplicate(char str[]) { 2 int length = strlen(str); 3 if (length > 1) { 4 bool flag[256]; 5 memset(flag, 0, sizeof(flag)); 6 for (int i = 0, j = 0; i < length; ++i) { 7 if (flag[str[i]] == false) { 8 flag[str[i]] = true; 9 str[j++] = str[i]; 10 } 11 } 12 //不要忘記加上結(jié)束標(biāo)志 13 str[length] = '\0'; 14 } 15 }如果不允許使用額外的數(shù)組來記錄字符是否出現(xiàn),那么就只有暴力搜查了。
1 void removeDuplicate(char str[]) { 2 int length = strlen(str); 3 if (length > 1) { 4 int k = 0; 5 for (int i = 0; i < length; ++i) { 6 bool found = false; 7 for (int j = 0; j < k; ++j) { 8 if (str[i] == str[j]) { 9 found = true; 10 break; 11 } 12 } 13 if (!found) { 14 str[k++] = str[i]; 15 } 16 } 17 //不要忘記結(jié)束標(biāo)記 18 str[k] = '\0'; 19 } 20 }測試用例如:"", "a", "aaa", "abab", "aabb", "abbbb", "abcd"...
轉(zhuǎn)載于:https://www.cnblogs.com/dengeven/p/3735608.html
總結(jié)
以上是生活随笔為你收集整理的【Cracking the Code Interview(5th edition)】一、数组与字符串(C++)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 路由器无线桥接 router wirel
- 下一篇: 【转载】PHP的(EOT)在PHP中添加