面试小结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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章