《程序員面試金典》習題解答(C/C++)

一.數據結構

1.數組與字符串

1.1  實現一個算法,肯定一個字符串的全部字符是否全都不一樣。假使不容許使用額外的數據結構,又該如何處理?ios

/*
假設字符集爲ASCII字符串,那麼字符串至多有256個字符,由於一旦大於256個則一定有兩個是相同的
*/
#include<iostream>
#include<string>
using namespace std;

bool isUniqueChars(string str){
    if (str.size() > 256)
        return false;
    bool char_set[256];
    for(int i = 0; i < str.size; ++i) {
        int val = str[i];    //獲取字符對應得ASCII碼
        if (char_set[val])    //這個字符已經在字符串中出現
            return false;
        char_set[val] = 1;
    }
    return true;
}

/*
假如輸入的字符只含有小寫字母a到z,則咱們只須要用一個int型變量
*/

bool isUniqueChar2(string str) {
    int flag = 0;
    if (str.size() > 26)
        return false;
    for (int i = 0; i < 26; ++i) {
        int val = str[i] - 'a';
        if (flag&(1 << val) > 0)
            return false;
        flag |= (1 << val);
    }
    return true;
}

1.2  用C或C++實現void reverse(char* str)函數,即反轉一個null結尾的字符串。算法

/*假設原地反轉,不分配額外空間,下面爲C語言實現*/
#include<stdio.h>

void reverse(char* str) {
    char* end = str;    
    char* start = str;
    char tmp;
    if (str) {
        while (*end)
            ++end;
    }
    --end;    /*回退一個字符,由於最後的字符爲null*/

    /*從首尾開始交換*/
    while (start < end) {
        tmp = *end;
        *end = *start;
        *start = tmp;
        ++start;
        --end;
    }
}

1.3  給定兩個字符串,請編寫程序,肯定其中一個字符串的字符從新排列後,可否變成另一個字符串。數組

/*給定兩個字符串,請編寫程序,肯定其中一個字符串的字符從新排列後,可否變成另一個字符串。*/
/*假設字符區分大小寫,空白字符也考慮在內,如下是兩種解法,使用C++*/
#include<iostream>
#include<string>
#include <algorithm>
using namespace std;

/*解法一:排序字符串,將兩個字符串進行排序後再進行比較*/
bool permutation1(string s, string t) {
    if (s.size() != t.size())
        return false;
    string s1 = s;
    string t1 = t;
    /*進行排序*/
    sort(s1.begin(), s1.end());    
    sort(t1.begin(), t1.end());
    if (s1 == t1)
        return true;
    return false;
}


/*解法二:比較兩個字符串各字符數是否相同*/
bool permutation2(string s, string t) {
    if (s.size() != t.size())
        return false;
    int count[256] = { 0 };
    /*計算s中各個字符出現的次數*/
    for (string::size_type i = 0; i !=s.size(); ++i) {
        int val = (int)s[i];
        count[val]++;
    }
    for (string::size_type j = 0; j != t.size(); ++j) {
        int c = (int) t[j];
        if (--count[c] < 0)
            return false;
    }
    return true;
}

1.4  編寫一個方法,將字符串中的空格所有替換成「%20」。假定該字符串尾部有足夠的空間存放新增字符,而且知道字符串的真實長度。例如,輸入:"Mr Jone Smith",輸出:「Mr20%Jone20%Smith」。數據結構

/*編寫一個方法,將字符串中的空格所有替換成「%20」。假定該字符串尾部有足夠的空間存放新增字符,而且知道字符串的真實長度。*/
/*例如,輸入:"Mr Jone Smith",輸出:「Mr20%Jone20%Smith」。*/

#include<iostream>
#include<string>
using namespace    std;

void replaceSpaces(char* str,int length) {
    int spaceCount = 0;
    for (int i = 0; i < length; ++i) {
        if (str[i] == ' ')
            ++spaceCount;
    }
    int newLength = length + spaceCount * 2;
    str[newLength] = '\0';
    int p = length - 1;
    int q = newLength - 1;
    while (p < q) {
        if (str[p] != ' ')
            str[q--] = str[p--];
        else
        {
            str[q--] = '0';
            str[q--] = '2';
            str[q--] = '%';
            p--;
        }
    }

}

1.5  利用字符重複出現的次數,編寫一個方法,實現基本的字符串壓縮功能。好比,字符串"aabcccccaaa"會變成「a2b1c5a3」。若「壓縮」後字符串沒有變短,則返回原先的字符串。函數

#include<iostream>
#include<string>
using namespace std;

string compress(string str) {
    if (str.empty())
        return NULL;
    string str1;
    char last = str[0];
    int count = 1;
    for (string::size_type i = 1; i < str.size(); ++i) {
        if (str[i] == last)
            ++count;
        else {
            str1.push_back(last);
            str1+=to_string(count);
            last = str[i];
            count = 1;
        }
    }
    /*由於最後一組重複字符還未放入壓縮字符串中就退出循環,因此還要更新最後一組字符*/
    str1.push_back(last);
    str1+=to_string(count);

    return str1.size() < str.size() ? str1: str;
 }

1.6  給定一幅由M*N矩陣表示的圖像,其中每一個像素的大小爲4字節,編寫一個方法,將圖像旋轉90度。不佔用額外內存空間可否作到?spa

/*假設順時針旋轉,*/
#include<iostream>
using namespace std;

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];

            //左到上
            matrix[first][i] = matrix[last - offset][first];

            //下到左
            matrix[last - offset][first] = matrix[last][last - offset];

            //右到下
            matrix[last][last - offset] = matrix[i][last];

            //上到右
            matrix[i][last = top;
        }
    }
}

 1.7  編寫一個算法,若M*N的矩陣中某個元素爲0,則將其所在的行與列清零。指針

void setZeros(vector<vector<int> > matrix) {
    bool *row= new bool[matrix.size()];
    bool *column= new bool[matrix[0].size()];

    //爲保險起見首先初始化爲false
    for (int i = 0; i < matrix.size(); ++i) {
        for (int j = 0; j < matrix[0].size(); ++j) {
            row[i] = false;
            column[j] = false;
        }
    }
    //記錄值爲0的元素所在的行的索引和列的索引
    for (int i = 0; i < matrix.size(); ++i) {
        for (int j = 0; j < matrix[0].size(); ++j) {
            if (matrix[i][j] == 0)
            {
                row[i] = true;
                column[j] = true;
            }
        }
    }

    //若行i或列j有個元素爲0,則matrix[i][j]置爲0
    for (int i = 0; i < matrix.size(); ++i) {
        for (int j = 0; j < matrix[0].size(); ++j) {
            if(row[i]||column[j])
                matrix[i][j] = 0;
        }
    }
    
}

1.8  假定有一個方法isSubstring,可檢查一個單詞是否爲其餘字符串的子串。給定兩個字符串s1和s2,請編寫代碼檢查s2是否爲s1旋轉而成,要求只能調用一次isSubstring。(好比,waterbottle是erbottlewat旋轉後的字符串)code

/*
*假設s2由s1旋轉而成,那麼咱們能夠找出旋轉點在哪。例如,若以wat旋轉waterbottle,就會獲得erbottlewat。
*咱們把字符串s1切分爲兩部分x和y,並將它們從新組合成s2.
*s1=xy=waterbottle
*x=wat
*yerbottle
*s2=yx=erbottlewat
*咱們須要確認的是有沒有辦法將s1切分紅xy=s1,yx=s2。不論xy的分割點在何處,xy都是xyxy的子串。也即s2是s1s1的子串
*/
#include<iostream>
using namespace std;

bool isRotation(string s1, string s2) {
    int len = s1.size();
    //檢查s1和s2是否等長且不爲空
    if (len == s1.size() && len > 0) {
        //憑藉s1和s1,放入新字符串中
        string s1s1 = s1 + s1;
        return isSubstring(s1s1, s2);
    }
    return false;
}

 

2.鏈表

2.1  編寫代碼,移除爲排序鏈表中的重複節點。進階:若是不得使用臨時緩衝區,該怎麼解決?blog

#include<iostream>
#include<map>
using namespace std;

//鏈表節點定義
struct Node {
    Node* next = NULL;
    int data;
};

/*解法一:採用散列表來存儲節點的值是否出現過,若重複,則刪除該節點。*/
void deleteDups1(Node *phead) {
    map<int, bool> imap;
    Node* previous = phead;
    Node* p = phead;

    while (p != NULL) {
        if (imap[p->data])
        {
            previous->next =p->next;
        }
        else {
            imap[p->data] = true;
            previous = p;

        }
        p = p->next;
    }
}

/*解法二:進階不使用額外緩衝區,使用兩個指針來迭代:current迭代訪問整個列表,runner用於檢查後續的節點是否重複*/
void deleteDups2(Node* phead) {
    if (phead == NULL)
        return;
    Node* current = phead;
    while (current != NULL) {
        Node* runner = current;
        while (runner->next != NULL) {
            if (current->data == runner->next->data) {
                current->next = runner->next->next;
            }
            else {
                runner = runner->next;
            }
            current = current->next;
        }
    }
}
相關文章
相關標籤/搜索