問題一:Implement an algorithm to determine if a string has all unique characters. What if you can not use additional data structures?
如果只是要判斷有沒有重複的字符,使用一個bool的數組是一個很簡單的方案:
bool isUniqueCharStr(string str){
bool carray[256];
int size = str.size();
for(int i = 0; i < size; ++i){
if(carray[ str[i] ]){
return false;
} else {
carray[ str[i] ] = true;
}
}
return true;
}
該算法的時間複雜度和空間複雜度都是O(n).考慮到題目中要求不使用額外的內存的話,可以以時間換取空間的方式,循環嵌套。
bool isUniqueCharStr_slow(string str){
int size = str.size();
for(int i = 0; i < size - 1; ++i){
for(int j = i+1; j < size; ++j){
if(str[j] == str[i]){
return false;
}
}
}
return true;
}
這種算法是暴力式遍歷,時間複雜度達到O(n^2),但是空間複雜度較低O(1)。
2. Write code to reverse a C-Style String. (C-String means that “abcd” is represented as five characters, including the null character.)
這個比較簡單,主要考察字符串以'\0'爲結束標誌,簡單寫一下代碼:
void reverse_c_str(char* str){
int len = strlen(str);
int i, j;
char tmp;
for(i = 0, j = len-1; i < j; i++, j--){
tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
}
值得注意的是,這裏strlen的時間複雜度爲O(n),當然,這是不可避免的,整個算法時間O(n),空間O(1)。
3.Design an algorithm and write code to remove the duplicate characters in a stringwithout using any additional buffer. NOTE: One or two additional variables are fine.An extra copy of the array is not
題目難點在於要使用O(1)的空間複雜度。可以把重複的字符標記成一個特殊字符,在第二遍遍歷時刪除。
void remove_dup_char2(char *str){
if( str == NULL) return;
int size = strlen(str);
if(size <= 2) return;
char flg = *str;
for(int i = 0; i < size-1; ++i){
for(int j = i+1; j < size; ++j){
if( str[j] == str[i] ){
str[j] = flg;
}
}
}
int idx = 1;
for(int i = 1; i < size; ++i){
if(str[i] == flg){
continue;
} else {
str[idx] = str[i];
idx++;
}
}
str[idx] = '\0';
}
上面的算法時間複雜度O(n^2),空間複雜度O(1)。
4. Write a method to decide if two strings are anagrams or not.
題目要求判斷兩個string是不是“變位詞”,所謂“變位詞”就是指,兩個單詞中所包含的字母相同只是順序不同。比較直觀的方法是對每個string中字符出現的個數進行統計,然後再進行比較。
bool anagram(string str1, string str2)
{
int letters[256];
int num_chars = 0;
int num_completed = 0;
for(int i = 0; i < 256; i++)
{
letters[i] = 0;
}
int size1 = str1.size();
int size2 = str2.size();
for(int i = 0; i < size1; i++)
{
if(letters[ str1[i] ] == 0)
num_chars++;
letters[ str1[i] ]++;
}
for(int i = 0; i < size1; i++)
{
if(letters[ str2[i] ] == 0)
return false;
letters[ str2[i] ] --;
if(letters[ str2[i] ] == 0)
{
num_completed++;
if(num_chars == num_completed)
{
return i == size1-1;
}
}
}
}
算法時間複雜度O(n),空間複雜度O(n)。需要注意的是:連個string有可能是多長的字符串? 這樣可以根據字符串的規模選取count_char的類型。
5. Write a method to replace all spaces in a string with ‘%20’.
這個題目的主要難點在於,轉換之後的字符串要比轉換之前長很多,並且,書上給出的答案相當詭異,下面是書本上給出的解答:
public static void ReplaceFun(char[] str, int length) {
int spaceCount = 0, newLength, i = 0;
for (i = 0; i < length; i++) {
if (str[i] == ‘ ‘) {
spaceCount++;
}
}
newLength = length + spaceCount * 2;
str[newLength] = ‘\0’;
for (i = length - 1; i >= 0; i--) {
if (str[i] == ‘ ‘) {
str[newLength - 1] = ‘0’;
str[newLength - 2] = ‘2’;
str[newLength - 3] = ‘%’;
newLength = newLength - 3;
} else {
str[newLength - 1] = str[i];
newLength = newLength - 1;
}
}
}
方法本身很容易理解,但是,如果str後面的內存是已使用的,那麼會造成內存錯誤。
6 Given an image represented by an NxN matrix, where each pixel in the image is 4 bytes, write a method to rotate the image by 90 degrees. Can you do this in place?
簡單理解爲使用O(1)的輔助空間把一個NxN的int類型的矩陣旋轉90度。對於這個題,只要找到旋轉後的矩陣和旋轉前矩陣的座標關係就okay了。這個並不難,只要求出矩陣的轉秩矩陣,然後在對每行(順時針旋轉)或者每列(逆時針旋轉)逆序就行了。
void rotate_matrix(int a[10][10]){
if(a == NULL) return;
int tmp = 0;
for(int i = 0; i < 10; ++i){
for(int j = 0; j < 10; ++j){
tmp = a[i][j];
a[i][j] = a[j][i];
a[j][i] = tmp;
}
}
int j,k;
//假設順時針
for(int i = 0; i < 10; i++){
for(j = 0, k = 9; j < k; ++j, --k){
tmp = a[i][j];
a[i][j] = a[i][k];
a[i][k] = tmp;
}
}
}
時間複雜度O(n^2),空間複雜度O(1)。
原書中給出的解答是這樣的:
public static void rotate(int[][] matrix, int n) {
for (int layer = 0; layer < n / 2; ++layer) {
int first = layer;
int last = n - 1 - layer;
for(int i = first; i < last; ++i) {
int offset = i - first;
int top = matrix[first][i]; // save top
// left -> top
matrix[first][i] = matrix[last-offset][first];
// bottom -> left
matrix[last-offset][first] = matrix[last][last - offset];
// right -> bottom
matrix[last][last - offset] = matrix[i][last];
// top -> right
matrix[i][last] = top; // right <- saved top
}
}
}
8.Assume you have a method isSubstring which checks if one word is a substring of another. Given two strings, s1 and s2, write code to check if s2 is a rotation of s1 using only one call to isSubstring (i.e., “waterbottle” is a rotation of “erbottlewat”).
《編程之美》上的老題目了:
char a[] = "AABCD";
char b[] = "CDAA";
int i, j, res;
char tmp;
int len = strlen(a);
for(i = 0; i < len; i++){
tmp = a[0];
for(j = 0; j < len-1; j++){
a[j] = a[j+1];
}
a[len-1] = tmp;
if(strstr(a,b)){
printf("OK");
return 0;
}
}
printf("NOT OK");
這一章的例子都不難,但是要給出來一個比較完美的解答還是需要很多思考。要寫出“正確”的代碼就更需要細心。