最长公共子序例 和最长公共子串
最长公共子序例 与最长公共子串 的区别 子串要求在原字符串中是连续的,而子序列则只需保持相对顺序一致,并不要求连续。例如X = {a, Q, 1, 1}; Y = {a, 1, 1, d, f}那么,{a, 1, 1}是X和Y的最长公共子序列,但不是它们的最长公共字串。
一、最长公共子序例
只求最长子序例长度
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; int arr[499][499]; int main() { string str, str1; while (cin>>str>>str1) { memset(arr, 0, sizeof(arr)); int k = str.size(); int l = str1.size(); int count = 0; for (int i = 0; i < k; i++) { for (int j = 0; j < l; j++) { if (str[i] == str1[j]) { arr[i+1][j+1] = arr[i][j] + 1; }else { arr[i+1][j+1] = max(arr[i+1][j],arr[i][j+1]); } } } cout<<arr[k][l]<<endl; } }
二、最长公共子串
最长公共子串与最长公共子序例的不同是str[i] != str1[j] 的时候 arr[i][j] = 0 而不是 arr[i][j] = max(arr[i-1][j],arr[i][j-1]);
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; int arr[499][499]; int main() { string str, str1; while (cin>>str>>str1) { memset(arr, 0, sizeof(arr)); int k = str.size(); int l = str1.size(); int maxsum = 0; for (int i = 0; i < k; i++) { for (int j = 0; j < l; j++) { if (str[i] == str1[j]) { arr[i+1][j+1] = arr[i][j] + 1; if (maxsum < arr[i+1][j+1]) maxsum = arr[i+1][j+1] }else { arr[i+1][j+1] = 0; } } } cout<<maxsum<<endl; } }
三、最长递增子序例
设长度为N的数组为{a0,a1, a2, ...an-1),则假定以aj结尾的数组序列的最长递增子序列长度为L(j),则L(j)={ max(L(i))+1, i<j且a[i]<a[j] }。也就是说,我们需要遍历在j之前的所有位置i(从0到j-1),找出满足条件a[i]<a[j]的L(i),求出max(L(i))+1即为L(j)的值。最后,我们遍历所有的L(j)(从0到N-1),找出最大值即为最大递增子序列。时间复杂度为O(N^2)。
/* 有毒数组开到100超时开1000超内存 */ #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; int arr[100000]; int a[100000]; int main() { int n; while (scanf("%d", &n) != EOF) { memset(arr, 0, sizeof(arr)); for (int i = 0; i < n; i++) scanf("%d", &a[i]); int max = 0; for (int i = 1; i < n; i++) { for (int j = 0; j < i; j++) { if (a[j] < a[i] && arr[j] + 1 > arr[i]) { arr[i] = arr[j] + 1; if (arr[i] > max) max = arr[i]; } } } printf("%d ", max+1); } }
最长递增子序例解法二
二分法
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 9 //数组元素个数 int array[N] = {2, 1, 6, 3, 5, 4, 8, 7, 9}; //原数组 int B[N]; //在动态规划中使用的数组,用于记录中间结果,其含义三言两语说不清,请参见博文的解释 int len; //用于标示B数组中的元素个数 int LIS(int *array, int n); //计算最长递增子序列的长度,计算B数组的元素,array[]循环完一遍后,B的长度len即为所求 int BiSearch(int *b, int len, int w); //做了修改的二分搜索算法 int main() { printf("LIS: %d ", LIS(array, N)); int i; for(i=0; i<len; ++i) { printf("B[%d]=%d ", i, B[i]); } return 0; } int LIS(int *array, int n) { len = 1; B[0] = array[0]; int i, pos = 0; for(i=1; i<n; ++i) { if(array[i] > B[len-1]) //如果大于B中最大的元素,则直接插入到B数组末尾 { B[len] = array[i]; ++len; } else { pos = BiSearch(B, len, array[i]); //二分查找需要插入的位置 B[pos] = array[i]; } } return len; } //修改的二分查找算法,返回数组元素需要插入的位置。 int BiSearch(int *b, int len, int w) { int left = 0, right = len - 1; int mid; while (left <= right) { mid = left + (right-left)/2; if (b[mid] > w) right = mid - 1; else if (b[mid] < w) left = mid + 1; else //找到了该元素,则直接返回 return mid; } return left;//数组b中不存在该元素,则返回该元素应该插入的位置 }
四’最大子串和
void solve() { int sum = 0; int max = -0xfff; for (int i = 0; i < n; i++) { sum += arr[i]; if (sum > max) { max = sum; }else if (sum < 0) { sum = 0; } } }