面試小結2

面試小結

TX
1. 鏈表反轉
2. 最大公共子串(兩種方法,動態規劃那種)
3. 進程與線程區別
4. 爲何轉後臺
5. 棧空間的最大值是多少

最大公共子串:

int LCS(char s1[], char s2[])
{
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    int **c = new int *[len1 + 1];
    for (int i = 0; i < len1 + 1; i++)
        c[i] = new int[len2 + 1];
    for (int i = 0; i < len1 + 1; i++)
        c[i][0] = 0;
    for (int j = 0; j < len1 + 1; j++)
        c[0][j] = 0;
    int max = -1, x = 0, y = 0;//max分別表示最大的公共子串長度。x與y分別表示下標
    for (int i = 1; i < len1 + 1; i++)
        for (int j = 1; j < len2 + 1; j++)
        {
            if (s1[i - 1] == s2[j - 1])
                c[i][j] = c[i - 1][j - 1] + 1;
            else
                c[i][j] = 0;
            if (c[i][j]>max)
            {
                max = c[i][j];
                x = i;
                y = j;
            }
        }
    if (max > 0)
    {
        int i = x - 1, j = y - 1, k = max;
        char *s = new char[k];
        s[k] = '\0';
        k--;
        while (k >= 0)
        {
            s[k--] = s1[i];
            i--;
        }
        cout << "最大公共子串是: " << s << endl;
    }
    return max;
}

講解:
用c[i][j]來表示 以s1的第i個字母爲結束的子串和以s2的第j個字母結束的子串所擁有的最大子串長度。
注意:必須包含s1[i]和s2[j]

則如果s1[i]==s2[j]
c[i][j]=c[i-1][j-1]+1
否則
c[i][j]=0。

求解時,先聲明一個變量來存儲結果:c[len1+1][en2+1];
爲何要聲明爲(len1+1)*(len2+1)這個長度,是因爲我們要初始化兩個邊界:c[0][0~len1]和c[0~len2][0]。它們開始都是0,所以需要多1個長度。
然後根據遞推公式計算可得。

最長公共子序列

c[i][j]表示字符串s1的前i個和字符串s2的前j個所能有的最長公共子序列。注意這裏的實際含義和前面的最長公共連續子串是不一樣的!!!
遞推公式:

if(s1[i]==s2[j])
    c[i][j]=c[i-1][j-1]+1;
else
    c[i][j]=max(c[i-1][j],c[i][j-1]);

注意打印時調用PrintlongestSubSequence,遞歸打印!!!

void PrintlongestSubSequence(int **b, char s1[], int i, int j)
{
    if (i == 0 || j == 0)
        return;
    if (b[i][j] == 0)
    {
        PrintlongestSubSequence(b, s1, i - 1, j - 1);
        cout << s1[i-1] << " ";
    }
    else if(b[i][j]==1)
        PrintlongestSubSequence(b, s1, i - 1, j);
    else
        PrintlongestSubSequence(b, s1, i, j - 1);
}

int longestSubSequence(char s1[], char s2[])
{
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    int **c = new int*[len1 + 1];
    int **b = new int*[len1 + 1];
    for (int i = 0; i < len1 + 1; i++)
    {
        c[i] = new int[len2 + 1];
        b[i] = new int[len2 + 1];
    }
    for (int i = 0; i < len1 + 1; i++)
        c[i][0] = 0;
    for (int j = 0; j < len2 + 1; j++)
        c[0][j] = 0;

    for (int i = 1; i < len1 + 1; i++)
        for (int j = 1; j < len2 + 1; j++)
        {
            if (s1[i - 1] == s2[j - 1])
            {
                c[i][j] = c[i - 1][j - 1] + 1;
                b[i][j] = 0;//是爲了保存結果下標
            }
            else
            {
                c[i][j] = max(c[i - 1][j], c[i][j - 1]);
                if (c[i - 1][j]>c[i][j - 1])
                    b[i][j] = 1;
                else
                    b[i][j] = -1;
            }   
        }
    PrintlongestSubSequence(b, s1, len1, len2);
    return c[len1][len2];
}

擴展:尋找三個串的最長子序列或者子串

http://blog.csdn.net/hackbuteer1/article/details/6686925

最長遞增子序列


int LISS(const int array[], size_t length, int result[])
{
    int *c=new int[length];//表示以第i個字母作爲結束得到的最長遞增子串長度
    int *pre = new int[length];//以第i個字母作爲結束得到的最長遞增子串,其前一個元素下標
    for (int i = 0; i < length; i++)
    {
        c[i] = 1;
        pre[i] = i;
    }
    int max = 1,k=0;
    //c[i]就是c[j](j=0,1,...,i-1)中滿足array[j]<c[i]的子串+1
    for (int i = 1; i < length; i++)
    {
        for (int j = 0; j < i;j++)
            if (array[i]>array[j]&&c[i]<c[j]+1) // 如果要求非遞減子序列只需將array[j] < array[i]改成 <= ,//如果要求遞減子序列只需改爲> 
            {
                c[i] = c[j] + 1;
                pre[i] = j;
                if (c[i] > max)
                {
                    max = c[i];
                    k = i;
                }
            }
    }

    int index = max - 1;
    while (pre[k] != k)
    {
        result[index--] = array[k];
        k = pre[k];
    }
    result[index] = array[k];//最後一個
    return max;

}
發佈了159 篇原創文章 · 獲贊 481 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章