最长子序列相关问题
2014-11-03 20:25
141 查看
单调递增最长子序列
时间限制:3000 ms | 内存限制:65535 KB难度:4
描述求一个字符串的最长递增子序列的长度
如:dabdbf最长递增子序列就是abdf,长度为4
输入第一行一个整数0<n<20,表示有n个字符串要处理
随后的n行,每行有一个字符串,该字符串的长度不会超过10000
输出输出字符串的最长递增子序列的长度
样例输入
3 aaa ababc abklmncdefg
样例输出
1 3 7
法一:
#include <stdio.h> #define MAX 10009 int d[MAX];//记录长度数组 int main() { int n, i, j, ma; scanf("%d", &n); char s[MAX]; while(n--) { scanf("%s", s); ma = 0; for(i = 0; s[i] != 0; i++) d[i] = 1;//最开始初始化为1,倘若没有最长子序列,则把它自身当做最长子序列,即为1 for(i = 0; s[i] != 0; i++) { for(j = i + 1; s[j] != 0; j++) {//从i之后开始把整个数组遍历一遍,可能有点费时 if(s[j] > s[i] && d[j] < d[i] + 1) {//至于这里为什么会d[j]<d[i]+1我还没搞太明白,这个创造者也的确很牛 d[j] = d[i] + 1; } } } for(i = 0; s[i] != 0; i++) { if(ma < d[i]) { ma = d[i]; } } printf("%d\n", ma); } return 0; }法二:
#include <stdio.h> #include <string.h> #define MAX 10009 int d[MAX]; int main() { int n, len, i, j, ma; scanf("%d", &n); char s[MAX]; while(n--) { ma = 0; scanf("%s", s); len = strlen(s); for(i = 0; i < len; i++) d[i] = 1; for(i = len - 2; i >= 0; i--) {//相对于上一个,这里做了一下改进,从最末开始,这样遍历的数组长度也比较少,时间复杂度稍微改进一点 for(j = i + 1; j <= len - 1; j++) { if(s[i] < s[j] && d[i] < d[j] + 1) { d[i] = d[j] + 1; } } } for(i = 0; i < len; i++) { if(ma < d[i]) { ma = d[i]; } } printf("%d\n", ma); } return 0; }法三:
这里又做了一下优化,直接用变量叠加即可,类似于最优代码
#include <stdio.h> #include <string.h> #define MAX 10009 int main() { char s[MAX], a[MAX]; int n, i, j, cnt; scanf("%d", &n); while(n--) { scanf("%s", s); a[0] = 0; cnt = 1; for(i = 0; s[i] != 0; i++) { for(j = cnt - 1; j >= 0; j--) { if(s[i] > a[j])//这里是关键 { a[j + 1] = s[i]; if(j + 1 == cnt) cnt++; break ; } } } printf("%d\n", cnt - 1); } return 0; }
法三:
dp[i] 以 i 结尾的当然也包括 i 在内的最长递增子序列;
我经常犯的的一个错误是:dp[i] = d[j] + 1(j<i && s[j]<s[i] && j 是第一个成立的)
这是错误的 如:"123124” 对应的dp是 dp[0]=1;dp[1]=2;dp[2]=3; dp[3]=1;dp[4]=2;dp[5]=3;这就是一个错误列子;
正解:dp[i] = max( d[j] ) + 1(j<i && s[j]<s[i] 成立中的最大的一个 )
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int dp[10010]; char s[10010]; int main() { int n, len, i, j, ma; while(~scanf("%d", &n)) { scanf("%s", s); len = strlen(s); dp[0] = 1; for(i = 1; i < len; i++) { ma = 0; for(j = i - 1; j >= 0; j--) { if(s[i] > s[j] && ma < dp[j]) { ma = dp[j]; } } dp[i] = ma + 1; } ma = dp[0]; for(i = 1; i < len; i++) { if(ma < dp[i]) { ma = dp[i]; } } printf("%d\n", ma); } return 0; }
单调递增子序列(二)
时间限制:1000 ms | 内存限制:65535 KB难度:4
描述
给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度。
如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5。
输入有多组测试数据(<=7)
每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=100000)。
数据以EOF结束 。
输入数据保证合法(全为int型整数)!
输出对于每组测试数据输出整形数列的最长递增子序列的长度,每个输出占一行。
样例输入
7 1 9 10 5 11 2 13 2 2 -1
样例输出
5 1
思路:二分法,时间复杂度n*log(n)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int a[1000010], ans[1000010]; int fun(int len) { int i, j, k, left, right, mid; ans[0] = a[0]; k = 0; for(i = 1; i < len; i++) { if(ans[k] < a[i]) { k++; ans[k] = a[i]; continue; } left = 0; right = k; while(left <= right) { if(a[i] < ans[left]) { j = left; break ; } if(ans[right] < a[i]) { j = right + 1; break ; } mid = (left + right) / 2; if(ans[mid] < a[i]) { left = mid + 1; } else if(a[i] < ans[mid]) { right = mid - 1; } else { j = mid; break ; } } ans[j] = a[i]; } return k + 1; } int main() { int n, i; while(~scanf("%d", &n)) { for(i = 0; i < n; i++) { scanf("%d", &a[i]); } printf("%d\n", fun(n)); } return 0; }
最长公共子序列
时间限制:3000 ms | 内存限制:65535 KB难度:3
描述咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列。
tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。
输入第一行给出一个整数N(0<N<100)表示待测数据组数
接下来每组数据两行,分别为待测的两组字符串。每个字符串长度不大于1000.
输出每组测试数据输出一个整数,表示最长公共子序列长度。每组结果占一行。
样例输入
2 asdf adfsd 123abc abc123abc
样例输出
3 6
<pre name="code" class="cpp">#include <iostream> #include <cstdio> #include <cstring> #define MAX 1005 using namespace std; char s1[MAX], s2[MAX]; int dp[MAX][MAX]; int lcs(int len1, int len2) { int len = len1 > len2 ? len1 : len2; int i, j; for(i = 0; i < len; i++) { dp[i][0] = 0; dp[0][i] = 0; } for(i = 1; i <= len1; i++) { for(j = 1; j <= len2; j++) { if(s1[i - 1] == s2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { if(dp[i - 1][j] < dp[i][j - 1]) { dp[i][j] = dp[i][j - 1]; } else { dp[i][j] = dp[i - 1][j]; } } } } return dp[len1][len2]; } int main() { int n, len1, len2; scanf("%d", &n); while(n--) { scanf("%s%s", s1, s2); len1 = strlen(s1); len2 = strlen(s2); printf("%d\n", lcs(len1, len2)); memset(s1, 0, sizeof(s1)); memset(s2, 0, sizeof(s2)); } return 0; }优化了空间的。。。
#include <stdio.h> #include <string.h> char s1[1001], s2[1001]; int dp[1001], t, old, tmp; int main(){ scanf("%d", &t); getchar(); while(t--){ gets(s1); gets(s2); memset(dp, 0, sizeof(dp)); int lenS1=strlen(s1), lenS2=strlen(s2); for(int i=0; i<lenS1; i++){ old=0; //若s1[i]==s2[j], dp[i][j] = dp[i-1][j-1]+1 //否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1]) //此处进行了空间优化,old 代表 dp[i-1][j-1] //dp[j-1] 代表 dp[i][j-1], dp[j] 代表 dp[i-1][j] for(int j=0; j<lenS2; j++){ tmp = dp[j]; if(s1[i]==s2[j]) dp[j] = old+1; else if(dp[j-1]>dp[j])dp[j]=dp[j-1]; old = tmp; } } printf("%d\n", dp[lenS2-1]); } return 0; }
相关文章推荐
- nyoj 17 最长子序列相关问题
- 动态规划解最长子序列问题
- 最长子序列和问题
- _____________________________________动态规划之最长子序列问题______1:两个序列中的______________________________________
- 最长子序列问题(时间复杂度O(nlog(n))
- hdu 1160 DP 最长子序列问题
- 算法笔记:动态规划求解最长子序列问题
- ACM LIS 最长子序列问题
- 【C语言】最长子序列问题求解
- 动态规划之最长子序列问题
- 语音信号的短时自相关序列求解以及xcorr与autocorr问题
- 最长子序列相关
- 最长递增子序列问题 nyoj 17单调递增最长子序列 nyoj 79拦截导弹
- 合唱队(最长子序列问题)
- 动态规划5:求解最多航线问题(应用了最长子序列知识)
- 语音信号的短时自相关序列求解以及xcorr与autocorr问题
- 动态规划之最长子序列问题
- 公主和王子能在一起多久的问题+dp+最长公共子序列转最长子序列。
- 最长子序列问题——动态规划算法初解
- 动态规划之LCS最长子序列问题