最长上升子序列

来源:互联网 发布:网络舆论引导员工资单 编辑:程序博客网 时间:2024/06/10 19:25

刚刚开始学习动态规划,就从最长上升子序列(Longest Increasing Subsequence)开始吧。最长上升子序列是非常经典的动态规划的题目,也是很基础的题目。对于这题的有两种算法,时间复杂度分别为O(n*logn)和O(n^2) 。

动态规划求解思路分析:(O(n^2))

经典的O(n^2)的动态规划算法,设A[i]表示序列中的第i个数,F[i]表示从1到i这一段中以i结尾的最长上升子序列的长度,初始时设F[i] = 0(i = 1, 2, ..., len(A))。则有动态规划方程:F[i] = max{1, F[j] + 1} (j = 1, 2, ..., i - 1, 且A[j] < A[i])。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define N 10005int main(){      int n, b[N], len, max;      char str[N];      scanf("%d", &n);      while (n--)      {            scanf("%s", str);            len = strlen(str);            b[0] = max = 1;            for (int i=1; i<len; i++)            {                  int temp = 0;                  for (int j=0; j<i; j++)                        if (str[i]>str[j] && b[j]>=temp)                              temp = b[j];                  b[i] = temp+1;                  if (b[i]>max)                        max = b[i];            }            printf("%d\n", max);      }      return 0;}

贪心+二分查找:(O(nlogn))   
开辟一个栈,每次取栈顶元素s和读到的元素a做比较,如果a>s,  则加入栈;如果a<s,则二分查找栈中的比a大的第1个数,并替换。  最后序列长度为栈的长度。  
这也是很好理解的,对x和y,如果x<y且E[y]<E[x],用E[x]替换  E[y],此时的最长序列长度没有改变但序列Q的''潜力''增大。  
举例:原序列为1,5,8,3,6,7  
栈为1,5,8,此时读到3,则用3替换5,得到栈中元素为1,3,8,  再读6,用6替换8,得到1,3,6,再读7,得到最终栈为1,3,6,7  ,最长递增子序列为长度4。

这里没有开辟栈,而是开了数组b[],全部赋为最大值。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define N 10005int binary(int a[], int len, int ch)//返回x,a[x]>=ch>a[x-1]{      int left = 1, right = len;      int mid = (left+right)>>1;      while (left<=right)      {            if (a[mid]>ch)                  right = mid-1;            else if (a[mid]<ch)                  left = mid+1;            else return mid;            mid = (left+right)>>1;      }      return left;}int main(){      int n, b[N], len, max;      char str[N];      scanf("%d", &n);      while (n--)      {            scanf("%s", str);            len = strlen(str);            for (int i=0; i<N; i++)                  b[i] = N;            b[0] = -1, b[1] = str[0];            max = 1;            for (int i=1; i<len; i++)            {                  int t = binary(b, N, str[i]);                  b[t] = str[i];                  if (t>max)                        max = t;            }            printf("%d\n", max);      }      return 0;}


对于如果要输出一个最长上升子序列的话,就要用到时间复杂度为O(n^2)的算法,就要多开辟一个数组pre[],用来存在每一个元素的前驱元素的数组下标。

核心代码如下:

for (int i=1; i<len; i++){     int temp = 0;     for (int j=0; j<i; j++)          if (str[i]>str[j] && b[j]>temp)          {               temp = b[j];               pre[i] = j;//存放前驱元素所在下标           }     b[i] = temp+1;}