【Cracking the Code Interview(5th edition)】一、数组与字符串(C++)
1.1 實現一個算法,確定一個字符串的所有字符是否全都不同。不允許使用額外的數據結構。
解答:這里假定字符集為ASCII碼,可以與面試官溝通確認字符串使用的字符集。由于字符集是有限的,建立一個數組模擬的Hash表記錄每個字符是否出現,線性掃描一次字符串即可,復雜度O(len(s)).如果字符集較大,需要考慮空間開銷,則可以用bitset來實現。
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 }可以加一個剪枝:如果字符串的大小大于字符集的大小了,那么該字符串肯定是存在重復字符的。
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 }補充:假設對空間開銷非常嚴苛,可以考慮先對字符串中的字符排序,然后進行一次線性掃描;如果還不允許改變字符串原有的內容,那么就只能暴力搜查了吧。
1.2 用C或C++實現void reverse(char * str)函數,即反轉一個‘\0’結尾的字符串。
解答:
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碼,假定判斷字符串相等時,大小寫是區分的。在開始時通過檢查兩個字符串長度是否相等進行剪枝,然后,用一個數組記錄第一個字符串中每個字符出現的次數,然后判斷第二個字符串中每個字符出現的次數是否與第一個字符串相等即可。
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"
解答:需要改變字符串長度的問題,通常從尾部開始處理比較高效,因為可以避免字符的重復移動。
1 void replaceSpace(char str[], int length) { 2 //length為字符串實際長度,不包括結尾的'\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 利用字符重復出現的次數,編寫一個方法,實現基本的字符串壓縮功能。比如:字符串"aabbcccccaaa"會變為"a2b1c5a3".若壓縮后的字符串沒有變短,則返回原先的字符串。
解答:重復長度編碼(run length encoding, RLE).按照題述模擬即可,但要注意細節實現。(其中to_string(int)函數為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 //開始忘記了加這一句,導致最后一組計數結果沒有加入ret 18 ret = ret + buf + to_string(cnt); 19 } 20 //注意這里要加等號 21 return ret.size() >= s.size() ? s : ret; 22 }1.6 給定一副NxN矩陣表示的圖像,其中每個圖像的大小為4字節,編寫一個方法,將圖像旋轉90°。不占用額外空間能否做到?
解答:常見的問題了,有很多旋轉的方式,這里就用最常用的由外向內逐層旋轉的方法吧。
?這里需要特別注意旋轉過程中的循環停止條件和對應的坐標,不小心非常容易出錯,用含義清晰的變量名有利于理清思路,避免錯誤。
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 }另外關于參數傳遞的問題,這里需要的是一個可變長的二維數組,C++中我們只能通過傳遞一個二級指針來實現,這樣在函數調用的時候就需要一些處理了:
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++中不能直接給函數傳遞二維數組的原因是:“數組名被改寫成一個指針參數”規則并不是遞歸定義的。數組的數組會被改寫成“數組的指針”,而不是“指針的指針”。
?1.7 編寫一個算法,若MxN的矩陣中某個元素為0,則將其所在的行與列都清零。
解答:LeetCode上也有這道題。可以用一個長度為M的數組和一個長度為N的數組分別記錄有0的行和列。此外也可以利用矩陣本身的存儲空間,用其中的一行一列來記錄該結果。以下代碼基于后一種方法。
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 //矩陣按規則置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旋轉而成,要求只能調用一次isSubstring.(比如:waterbottle是erbottlewat旋轉后的字符串)
解答:s2是s1經過一次旋轉得到的,那么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 }補充:第四版中的習題
1.3 設計算法并編碼實現:在不使用額外緩沖區的情況下去除字符串中的重復字符。設計一些測試用例。
解答:如果允許開辟與字符串長度無關大小的數組,則可以用一個記錄字符是否出現過的數組來實現。
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 //不要忘記加上結束標志 13 str[length] = '\0'; 14 } 15 }如果不允許使用額外的數組來記錄字符是否出現,那么就只有暴力搜查了。
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 //不要忘記結束標記 18 str[k] = '\0'; 19 } 20 }測試用例如:"", "a", "aaa", "abab", "aabb", "abbbb", "abcd"...
轉載于:https://www.cnblogs.com/dengeven/p/3735608.html
總結
以上是生活随笔為你收集整理的【Cracking the Code Interview(5th edition)】一、数组与字符串(C++)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 路由器无线桥接 router wirel
- 下一篇: 【转载】PHP的(EOT)在PHP中添加