CLRS 15.4最长公共子序列

来源:互联网 发布:如何把mac里的照片导出 编辑:程序博客网 时间:2024/06/05 14:40

15.4-1
这里写图片描述
对应的LCS为 1,0,0,1,1,0
下面的程序可以验证这个答案

#include <iostream>#include <string>using std::cout;using std::cin;using std::endl;using std::string;void LCS_LENGTH(string &x,string &y,int **b,int **c){    int m = x.size();    int n = y.size();    for(int i = 1; i <= m; i++)        c[i][0] = 0;    for(int j = 0; j <= n; j++)        c[0][j] = 0;    for(int i = 1; i <= m; i++)    {        for(int j = 1; j <= n; j++)        {            if(x[i-1] == y[j-1])            {                c[i][j] = c[i-1][j-1] + 1;                b[i][j] = 0;            }            else if(c[i-1][j] >= c[i][j-1])            {                c[i][j] = c[i-1][j];                b[i][j] = 1;    //up            }            else            {                c[i][j] = c[i][j-1];                b[i][j] = 2;    //left            }        }    }}void PRINT_LCS(int **b,string &x,int i,int j){    if(i == 0 || j == 0)        return;    if(b[i][j] == 0)    {        PRINT_LCS(b,x,i-1,j-1);        cout << x[i-1];    }    else if(b[i][j] == 1)        PRINT_LCS(b,x,i-1,j);    else PRINT_LCS(b,x,i,j-1);}int main(){    string x,y;    cout << "Enter two strings:";    cin >> x >> y;    cout << endl;    int m = x.size(),n = y.size();    int **b = new int *[m+1];    int **c = new int *[m+1];    for(int i = 0; i <= m; i++)    {        b[i] = new int[n+1];        c[i] = new int[n+1];    }    LCS_LENGTH(x,y,b,c);    PRINT_LCS(b,x,m,n);    cout << endl;    for(int i = 0; i <= m; i++)    {        delete []b[i];        delete []c[i];    }    delete []b;    delete []c;    return 0;}

15.4-2
伪代码如下:

PRINT_LCS(c, x, y, i, j)    if i = 0 || j = 0        return    if x[i] = y[j]        PRINT_LCS(c, x, y, i-1, j-1)        print x[i]    elif c[i-1, j] >= c[i, j-1]        PRINT_LCS(c, x, y, i-1, j)    else        PRINT_LCS(c, x, y, i, j-1)

修改第一题的LCS-LENGTH,PRINT-LCS,代码如下。

void LCS_LENGTH(string &x,string &y,int **c){    int m = x.size(), n = y.size();    for(int i = 1; i <= m; i++)        c[i][0] = 0;    for(int j = 0; j <= n; j++)        c[0][j] = 0;    for(int i = 1; i <= m; i++)    {        for(int j = 1; j <= n; j++)        {            if(x[i-1] == y[j-1])                c[i][j] = c[i-1][j-1] + 1;            else if(c[i-1][j] >= c[i][j-1])                c[i][j] = c[i-1][j];            else c[i][j] = c[i][j-1];        }    }}void PRINT_LCS(int **c,string &x,string &y,int i,int j){    if(i == 0 || j == 0)        return;    if(x[i-1] == y[j-1])    {        PRINT_LCS(c,x,y,i-1,j-1);        cout << x[i-1];    }    else if(c[i-1][j] >= c[i][j-1])        PRINT_LCS(c,x,y,i-1,j);    else PRINT_LCS(c,x,y,i,j-1);}

15.4-3
伪代码如下:

LCS-LENGTH(X, Y)    m = X.length    n = Y.length    let c[0..m,0..n]and b[1..m,1..n] be new tables    for i = 1 to m        for j = 1 to n            c[i,j] = -1    LCS-LENGTH-AUX(X,Y,m,n,c,b)    return c and bLCS-LENGTH-AUX(X,Y,i,j,c,b)    if c[i,j] > -1        return c[i,j]    if i = 0 or j = 0        c[i,j] = 0    else        if X[i] == Y[j]            c[i,j] = LCS-LENGTH-AUX(X,Y,i-1,j-1,c,b)            b[i,j] = "↖"        elseif LCS-LENGTH-AUX(X,Y,i,j-1,c,b) >= LCS-LENGTH-AUX(X,Y,i-1,j,c,b)            c[i,j] = c[i,j-1]            b[i,j] = "←"        else  c[i,j] = c[i-1,j]              b[i,j] = "↑"    return c[i][j]

可运行代码如下:

int LCS_LEGNTH_AUX(string &x,string &y,int **b,int **c,int i,int j){    if(c[i][j] > -1)        return c[i][j];    if(i == 0 || j == 0)        c[i][j] = 0;    else    {        if(x[i-1] == y[j-1])        {            c[i][j] = LCS_LEGNTH_AUX(x,y,b,c,i-1,j-1) + 1;            b[i][j] = 0;        }        else if(LCS_LEGNTH_AUX(x,y,b,c,i-1,j) >= LCS_LEGNTH_AUX(x,y,b,c,i,j-1))        {            c[i][j] = LCS_LEGNTH_AUX(x,y,b,c,i-1,j);            b[i][j] = 1;  //up        }        else        {            c[i][j] = LCS_LEGNTH_AUX(x,y,b,c,i,j-1);            b[i][j] = 2;  //left        }    }    return c[i][j];}void LCS_LENGTH(string &x,string &y,int **b,int **c){    int m = x.size(), n = y.size();    for(int i = 1; i <= m; i++)        for(int j = 1; j <= n; j++)            c[i][j] = -1;    LCS_LEGNTH_AUX(x,y,b,c,m,n);}

15.4-4
1、使用 2×min(m,n)表项及 O(1) 的空间
先假设m = X.length,n = Y.length,并假设 Y 的长度小于 X 的长度(否则交换一下 X,Y 即可),然后利用 c[1.2,1...n] 来计算 LCS。分别称表 c 中的第一二行为前一行和当前行;简称当前行的下一行为下一行。因为求解一个项c[i,j],只会用到 c[i1,j1],c[i,j1],c[i1,j]。所以:
将前一行全部赋值 0,从左到右计算当前行;
当前行计算完之后,将当前行的值赋值给前一行,然后当前行变成下一行(即需要计算的下一个当前行)。

2、使用 min(m,n)表项及 O(1) 的空间
原理和上面类似,不同的是,我们把 c[1...n] 分成两部分对待,计算当前行第 k 个元素时,前 k1 个已经保存在 c[1..k1] 中,而 c[k..n] 还保存的是“前一行”的内容,用一个额外的空间 val 保存 c[i1,j1],比较 c[k1],val,c[k] 然后更新 c[k] 即可。

15.4-5
思路就是:得到序列X 排序后的序列Y,求出X,Y的 LCS 即可。

15.4-6
O(nlgn) 求最长单调递增子序列可以在网上找到很多答案,我在这就不证明算法思想,只是简单举例说明怎么得出答案的。
假设数组 A3,2,8,9,4,我们用一个同样长度的数组 B 考察这个序列 A
首先 A[1]=3(数组从1开始计数),所以 B[1]=3,得到序列为3
接下来 A[2]=2,B[1]=3>2,更新B[1]=2,得到序列为2
接着A[3]=8>B[1]=2,将A[3] 插入到数组B,即B[2]=8,得到序列为2,8
然后A[4]=9>B[2]=8,同上使得B[3]=9;得到序列为2,8,9
最后A[5]=4,小于B[2],B[3],更新B[2]=4,此时序列为2,4,9
注意,这个2,4,9并不是我们求出的最后子序列结果,而是表示最长子序列长度为 3,那为什么要在最后一步替换2,8,9为2,4,9呢?明明正确答案就是2,8,9啊!!!因为如果数组 A 为3,2,8,9,4,7,9的话,我们按照上面所说的步骤就会得到2,4,7,9对于长度为 4 的最长单调子序列,而如果不替换则得不到这个结果!
贴一个Leetcode通过的代码

class Solution {public:    int lengthOfLIS(vector<int>& nums) {        if(nums.empty())            return 0;        int n = nums.size();        int *c = new int[n];        int LIS_len = 1;        c[0] = nums[0];        for(int i = 1; i < n; i++)        {            int index = binary_search(c,0,LIS_len - 1,nums[i]);            if(index == LIS_len)                c[LIS_len++] = nums[i];            else c[index] = nums[i];        }        delete []c;        return LIS_len;    }    int binary_search(int *array,int low,int high,int key)//返回第一个大于key的数组下标    {        while(low <= high)        {            int mid = (low + high) / 2;            if(array[mid] == key)                return mid;            else if(array[mid] < key)                low = mid + 1;            else high = mid - 1;        }        if(high < 0)            return 0;        else return high + 1;    }};
0 0
原创粉丝点击