最长上升子序列

来源:互联网 发布:数据分析技术 编辑:程序博客网 时间:2024/06/09 13:42

最长上升的O(n^2)的方法是我看过最简单的DP了~~

拿POJ 2533来说。

Sample Input

7
1 7 3 5 9 4 8

Sample Output(最长上升/非降子序列的长度)

4

从输入的序列中找出最长的上升子序列(LIS)。

d(i)=max(1,d(j)+1)其中(a[i]>a[j])其中这里的i,j均为下标。

含义是讨论到第i个数的最长上升子序列,要么是1,即都比前面的小,否则一定是由前面某一个dp(j)其中(a[j]<a[i])加1得到.

当然最后得到的总体的最长上升序列的长度为dp数组中的最大值,注意不是最后一个比如2,3,5,1前面3个数,每一个数的dp都是由前面的dp中最大+1继承而来,而最后一个比前面每一个数都小。

#include <stdio.h>#include <string.h>int dp[10001];int a[1001]; int main() {     int n,m,i,j,max;     while(scanf("%d",&n)==1)     {     memset(a,0,sizeof(a));     memset(dp,0,sizeof(dp));     for (i=1;i<=n;i++)        scanf("%d",&a[i]);        max=0;    for (i=1;i<=n;i++)     {         dp[i]=1;         for (j=1;j<=i-1;j++)            if ((a[j]<a[i])&&(dp[i]<dp[j]+1))//每一次只需要加那个前面dp(j)的最高一次,而如果加了就是dp(i)=dp(j)+1即如果dp(i)如果小于dp(j)+1就要更新,否则肯定保持当前较大的dp(i)         {             dp[i]=dp[j]+1;         }         if (dp[i]>max)            max=dp[i];     }     printf("%d\n",max);     }     return 0; }

这个解法不是我想的,从网上学来的,这里面与大家分享一下。这个算法的复杂度只有O(nlogn),在有大量数据的情况下,这算法效率极高。。。

(摘录原作者的话)

这个算法其实已经不是DP了,有点像贪心。至于复杂度降低其实是因为这个算法里面用到了二分搜索。本来有N个数要处理是O(n),每次计算要查找N次还是O(n),一共就是O(n^2);现在搜索换成了O(logn)的二分搜索,总的复杂度就变为O(nlogn)了。

这个算法的具体操作如下(by RyanWang):

开一个栈,每次取栈顶元素top和读到的元素temp做比较,如果temp > top 则将temp入栈;如果temp < top则二分查找栈中的比temp大的第1个数,并用temp替换它。 最长序列长度即为栈的大小top。

这也是很好理解的,对于x和y,如果x < y且Stack[y] < Stack[x],用Stack[x]替换Stack[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。

#include <stdio.h>int s[1001]; int main() {     int i,n,top,temp;     while(scanf("%d",&n)==1)     {     top=0;     s[top]=-1;//保证最小     for (i=1;i<=n;i++)     {         scanf("%d",&temp);         if (temp>s[top])//如果比栈顶元素大则入栈成为栈顶元素            s[++top]=temp;         else//否则二分查找比temp大的第一个数         {             int low=1;             int high=top;             int middle;             while(low<=high)             {                 middle=(low+high)/2;                 if (s[middle]<temp)                    low=middle+1;                 else                    high=middle-1;             }             s[low]=temp;//用temp代替比temp大的第一个数代替,总数不变         }     }     printf("%d\n",top);     }     return 0; }





0 0