假设有:两个序列 X、Y 为例子:
Xm = x1 x2 x3 ... xm
Yn = y1 y2 y3 ... yn
有f(m, 0) = f(0, m) = 0
如果xm != yn, 则f(m, n) = max{ f(m-1, n), f(m, n-1) }
如果xm = yn,则f(m, n) = f(m-1, n-1) + 1
此时,二维数组中最大的数便是 X 和 Y 的最长公共子序列的长度,依据该数组回溯,便可找出最长公共子序列。
该算法的时间和空间复杂度均为O(m*n), 由于计算新的行的值,只需要保存上一行的值作为依赖,而不必要前面计算的所有的行都保存,所以空间复杂度可以降为min(O(2m),O(2n))。
#include <stdio.h>
#include <string.h>
int LCS(char szArrayA[], int iANum, char szArrayB[], int iBNum)
{
int i, j;
int szArray[iANum + 1][iBNum + 1];
memset(szArray, 0, sizeof(szArray));
for(i = 0; i < iANum; ++i)
{
for(j = 0; j < iBNum; ++j)
{
if(szArrayA[i] == szArrayB[j])
{
szArray[i+1][j+1] = szArray[i][j] + 1;
}
else
{
szArray[i+1][j+1] = szArray[i][j+1] > szArray[i+1][j] ? szArray[i][j+1] : szArray[i+1][j];
}
printf("%d ", szArray[i+1][j+1]);
}
printf("\n");
}
return szArray[iANum][iBNum];
}
// 时间复杂度为O(m*n),空间复杂度为O(n)。
int LCS1(char szArrayA[], int iANum, char szArrayB[], int iBNum)
{
int i, j;
int *pLastRow, *pRow, *pTmp;
printf("iANum = %d, iBNum =%d\n", iANum, iBNum);
if(iANum > iBNum)
{
int szArray[2*(iBNum+1)];
memset(szArray, 0, sizeof(szArray));
pLastRow = szArray;
pRow = &szArray[iBNum+1];
for(i = 0; i < iANum; ++i)
{
for(j = 0; j < iBNum; ++j)
{
if(szArrayA[i] == szArrayB[j])
{
pRow[j+1] = pLastRow[j] + 1;
}
else
{
pRow[j+1] = pLastRow[j+1] > pRow[j] ? pLastRow[j+1] : pRow[j];
}
printf("%d ", pRow[j+1]);
}
printf("\n");
pTmp = pLastRow;
pLastRow = pRow;
pRow = pTmp;
}
return pLastRow[iBNum];
}
else
{
int szArray[2*(iANum + 1)];
memset(szArray, 0, sizeof(szArray));
pLastRow = szArray;
pRow = &szArray[iANum + 1];
for(i = 0; i < iBNum; ++i)
{
for(j = 0; j < iANum; ++j)
{
if(szArrayA[j] == szArrayB[i])
{
pRow[j+1] = pLastRow[j] + 1;
}
else
{
pRow[j+1] = pLastRow[j+1] > pRow[j] ? pLastRow[j+1] : pRow[j];
}
printf("%d ", pRow[j+1]);
}
printf("\n");
pTmp = pLastRow;
pLastRow = pRow;
pRow = pTmp;
}
return pLastRow[iANum];
}
}
问题2:
以两个序列 X、Y 为例子:
设有二维数组f(i,j) 表示 X 的 i 位和 Y 的 j 位之前的最长连续公共子序列的长度,则有:
f(m,0) = f(0,m) = 0;
如果x(m) != y(n), 则f(m,n) = 0
如果x(m) = y(n), 则f(m,n) = f(m-1,n-1) + 1
int LCS2(char szArrayA[], int iANum, char szArrayB[], int iBNum)
{
int i, j, iMaxLen = 0;
int szArray[iANum + 1][iBNum + 1];
memset(szArray, 0, sizeof(szArray));
for(i = 0; i < iANum; ++i)
{
for(j = 0; j < iBNum; ++j)
{
if(szArrayA[i] == szArrayB[j])
{
szArray[i+1][j+1] = szArray[i][j] + 1;
if (iMaxLen < szArray[i+1][j+1])
{
iMaxLen = szArray[i+1][j+1];
}
}
else
{
szArray[i+1][j+1] = 0;
}
printf("%d ", szArray[i+1][j+1]);
}
printf("\n");
}
return iMaxLen;
}
// 时间复杂度为O(m*n), 时间复杂度为O(m*n),空间复杂度为O(n)
int LCS3(char szArrayA[], int iANum, char szArrayB[], int iBNum)
{
int i, j, iMaxLen = 0;
int *pLastRow, *pRow, *pTmp;
printf("iANum = %d, iBNum =%d\n", iANum, iBNum);
if(iANum > iBNum)
{
int szArray[2*(iBNum+1)];
memset(szArray, 0, sizeof(szArray));
pLastRow = szArray;
pRow = &szArray[iBNum+1];
for(i = 0; i < iANum; ++i)
{
for(j = 0; j < iBNum; ++j)
{
if(szArrayA[i] == szArrayB[j])
{
pRow[j+1] = pLastRow[j] + 1;
}
else
{
pRow[j+1] = 0;
}
printf("%d ", pRow[j+1]);
}
printf("\n");
pTmp = pLastRow;
pLastRow = pRow;
pRow = pTmp;
}
return pLastRow[iBNum];
}
else
{
int szArray[2*(iANum + 1)];
memset(szArray, 0, sizeof(szArray));
pLastRow = szArray;
pRow = &szArray[iANum + 1];
for(i = 0; i < iBNum; ++i)
{
for(j = 0; j < iANum; ++j)
{
if(szArrayA[j] == szArrayB[i])
{
pRow[j+1] = pLastRow[j] + 1;
}
else
{
pRow[j+1] = 0;
}
printf("%d ", pRow[j+1]);
}
printf("\n");
pTmp = pLastRow;
pLastRow = pRow;
pRow = pTmp;
}
return pLastRow[iANum];
}
}
int main()
{
//char szArrA[] = "1A2C3D4B56", szArrB[] = "B1D23CA45B6A";
//char szArrA[] = "B1D23CA45B6A", szArrB[] = "1A2C3D4B56";
//char szArrA[] = "1D234B56", szArrB[] = "B1D23C";
char szArrA[] = "B1D23C", szArrB[] = "1D234B51D23C6";
int iLen = 0;
iLen = LCS(szArrA, sizeof(szArrA)/sizeof(szArrA[0])-1, szArrB, sizeof(szArrB)/sizeof(szArrB[0])-1);
printf("lcs = %d\n", iLen);
iLen = LCS1(szArrA, sizeof(szArrA)/sizeof(szArrA[0])-1, szArrB, sizeof(szArrB)/sizeof(szArrB[0])-1);
printf("lcs1 = %d\n", iLen);
iLen = LCS2(szArrA, sizeof(szArrA)/sizeof(szArrA[0])-1, szArrB, sizeof(szArrB)/sizeof(szArrB[0])-1);
printf("lcs2 = %d\n", iLen);
iLen = LCS3(szArrA, sizeof(szArrA)/sizeof(szArrA[0])-1, szArrB, sizeof(szArrB)/sizeof(szArrB[0])-1);
printf("lcs3 = %d\n", iLen);
return 0;
}