假設有:兩個序列 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;
}