您的位置:首页 > 其它

LIS(最长递增子序列)和LCS(最长公共子序列)的总结

2014-10-29 16:08 351 查看
LIS(最长递增子序列)和LCS(最长公共子序列)的总结

最长公共子序列(LCS):O(n^2)


两个for循环让两个字符串按位的匹配:i in range(1, len1) j in range(1, len2)

s1[i - 1] == s2[j - 1], dp[i][j] = dp[i - 1][j -1] + 1;

s1[i - 1] != s2[j - 1], dp[i][j] = max (dp[i - 1][j], dp[i][j - 1]);

初始化:dp[i][0] = dp[0][j] = 0;


伪代码:

dp[maxn1][maxn2];
s1[maxn1],s2[maxn2];
p[maxn1][maxn2][2];
//init
for i in range(0, len1):
dp[i][0] = 0;
else:;
for i in range(0, len2):
dp[0][i] = 0;
else:;

for i in range(1, len1):
for j in range(1, len2):
if s1[i] == s2[j]:
dp[i][j] = dp[i - 1][j - 1] + 1;
p[i][j][0] = i - 1;
p[i][j][1] = j - 1;
else:
if dp[i - 1][j] > dp[i][j - 1]:
dp[i][j] = dp[i - 1][j];
p[i][j][0] = i - 1;
p[i][j][1] = j;
else:
dp[i][j] = dp[i][j - 1];
p[i][j][0] = i;
p[i][j][1] = j - 1;
else:;
else:;
return dp[len1][len2];
//path 非递归
function print_path(len1, len2):
if (dp[len1][len2] == 0)
return;
printf_path(p[len1][len2][0], p[len1][len2][1]);
if s1[len1] == s2[len2]:
printf:s1[len1];
end function;


题目:UVA - 531Compromise

UVA - 10066The Twin Towers
UVA - 10192Vacation

uva10405 - Longest Common Subsequence

最长递增子序列(LIS):O(n^2)


从左到右的求前i长度的序列的最长递增子序列的长度,状态转移方程:

dp[i] = Max(dp[j] + 1);i in range(1, len); j in range(1, i - 1);


伪代码

s[maxn],dp[maxn];

for i in range(1, len):
dp[i] = 1;

int maxlen = 1;
for i in range(2, len):
for j range(1, i - 1):
if s[i] > s[j]:
dp[i] = Max(dp[i], dp[j] + 1);
else:
maxlen = max(maxlen, dp[i]);
else:;
return maxlen;
//path递归
function print_path(maxlen):
if maxlen == 0:return;

for i in range(1, len):
if dp[i] == maxlen:
print_path(maxlen - 1);
printf:s[i];
end function;


题目: UVA - 10599Robots(II)

最长递增子序列O(n * logn)


还是从左往右的求前i长度的序列的最长递增子序列长度,但是再确定dp[j]最大值的时候还要用一层循环来查找,这样比较低效.如果把前面的i长度序列出现的最长递增子序列储存起来,那么查找的时候用二分就可以做到O(logn)的复杂度。

用一个LIS数组来储蓄前i序列的最长递增子序列,查找第i个数字的时候,如果num[i] > LIS[top], 那么LIS[++top] = num[i]; dp[i] = top;如果num[i] == LIS[top],那么dp[i] = top; 如果num[i] < LIS[top], 那么二分查找到某个等于或者大于num[i]的最接近的值的位置(第k个),dp[i] = k - 1; LIS[k] = num[i];

题目:UVA - 10534Wavio Sequence

伪代码

dp[maxn], LIS[maxn], s[maxn];
top = 0;
LIS[top++] = s[1];

int maxlen = 1;
for i in range(2, len):
if s[i] > LIS[top]:
LIS[++top] = s[i];
dp[i] = top + 1;
else if s[i] == LIS[top]:
dp[i] = top + 1;
else:
k = lower_bound(LIS.begin(), LIS.end(), s[i]) - LIS.beign();
LIS[k] = s[i];
dp[i] = k + 1;

maxlen = max(maxlen, dp[i]);
else:;
return maxlen;


最长公共子序列O(n * logn)


要求串本身不会出现相同的数字或是字母。通过对第一个字符串进行映射(递增的顺序),然后第二个字符串依照上面的第一个字符串等价映射,这样就把问题从LCS转化成LIS。例如:

串1: 2 4 3 5 6

映射:1 2 3 4 5

串2: 3 2 6 8 10

等价映射:3 1 5 0 0

题目:uva10635Prince and Princess
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: