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 b
LCS-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
的长度小于
将前一行全部赋值 0,从左到右计算当前行;
当前行计算完之后,将当前行的值赋值给前一行,然后当前行变成下一行(即需要计算的下一个当前行)。
2、使用 min(m,n)
表项及
O(1)
的空间
原理和上面类似,不同的是,我们把
c[1...n]
分成两部分对待,计算当前行第
k
个元素时,前
15.4-5
思路就是:得到序列X
排序后的序列Y
,求出X,Y
的 LCS 即可。
15.4-6
用
O(nlgn)
求最长单调递增子序列可以在网上找到很多答案,我在这就不证明算法思想,只是简单举例说明怎么得出答案的。
假设数组 A
为 3,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;
}
};