最大上升序列算法

最长上升子序列问题:

给出一个由n个数组成的序列x[1..n],找出它的最长单调上升子序列。即求最大的m和a1,
a2……,am,使得a1<a2<……<am且x[a1]<x[a2]<……<x[am]。

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

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

令a[i]表示输入第i个元素,b[i]表示从a[1]到a[i]中以a[i]结尾的最长子序列长度。对于任意的0 <  j <= i-1,如果a(j) < a(i),则a(i)可以接在a(j)后面形成一个以a(i)结尾的新的最长上升子序列。对于所有的 0 <  j <= i-1,我们需要找出其中的最大值。

DP状态转移方程:

b[i] = max{1, b[j] + 1} (j = 1, 2, 3, ..., i-1 且 a[j] < a[i])

解释一下这个方程,i, j在范围内:

如果 a[j] < a[i] ,则b[i] = b[j] + 1

如果 a[j] >= a[i] ,则b[i] = 1

 1 #include <stdio.h>
 2 int a[10000],b[10000];
 3 int main()
 4 {
 5     int n, i, j, max;
 6     scanf("%d", &n);
 7     for(i=0;i<n;i++)
 8     {
 9         scanf("%d", &a[i]);
10         b[i] = 1;
11     }
12     for(i=n-1;i>=0;i--)
13         for(j=i;j<n;j++)
14             if(a[i]<a[j] && b[j]+1>b[i])
15                 b[i] = b[j]+1;
16     for(max=1,i=0;i<n;i++)
17         if(max < b[i])
18             max = b[i];
19         printf("%d\n", max);
20     return 0;
21 }

O(n*n)

2.贪心+二分查找:(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。

用数组模拟

#include <stdio.h>
int f(int a[], int n)
{
    int b[10100];
    int t, i, z ,y, mid;
    b[t=1] = a[0];
    for(i=1;i<n;i++)
        {
            if(a[i]>b[t])
                b[++t] = a[i];
            else
            {
                z=0;y=t;
                while(z<y)
                {
                     mid = (z+y)/2;
                    if(b[mid] > a[i])
                        y = mid;
                    else
                        z = mid+1;
                }
                b[z] = a[i];
            }
        }
    return t;
}
int main()
{
    int a[100011];
    int n, i, k;
    scanf("%d", &n);
    for(i=0;i<n;i++)
        scanf("%d", &a[i]);
    printf("%d\n", f(a, n));
    return 0;
}

O(nlogn)

推荐一些最大上升序列的题

poj:2533 http://poj.org/problem?id=2533

题解:

时间: 2024-12-09 10:03:37

最大上升序列算法的相关文章

algorithm之改变序列算法

简述:改变序列算法,参见http://www.cplusplus.com/reference/algorithm/?kw=algorithm /* template <class BidirectionalIterator, class UnaryPredicate> BidirectionalIterator partition (BidirectionalIterator first, BidirectionalIterator last, UnaryPredicate pred); Pa

有效的括号序列——算法面试刷题4(for google),考察stack

给定一个字符串所表示的括号序列,包含以下字符: '(', ')', '{', '}', '[' and ']', 判定是否是有效的括号序列. 括号必须依照 "()" 顺序表示, "()[]{}" 是有效的括号,但 "([)]" 则是无效的括号. 您在真实的面试中是否遇到过这个题? 样例 样例 1: 输入:"([)]" 输出:False 样例 2: 输入:"()[]{}" 输出:True 挑战 O(n)的时间

序列算法

区间查询&单点修改: 给定一个序列a,进行很多次操作:访问a[l ~~ r]的区间和;将a[i] 的值修改为 a[i] + k; 求区间x ~~ y中的区间和: 1 #include <cstdio> 2 #include <algorithm> 3 4 #define MAXN 2222 5 6 int n, m; 7 int a[MAXN], s[MAXN]; 8 9 int main() { 10 scanf("%d%d", &n, &am

信息安全-4:公钥密码体制之背包算法[原创]

转发注明出处:http://www.cnblogs.com/0zcl/p/6111686.html 前言 本来我是想学RSA算法的,但发现太难了,不是我能理解的,于是我先看教材前面的背包算法.不出意料的话会在下一篇博客介绍下RSA算法! 背包问题介绍: 给定一些物体,每个物体有不同的重量,是否有可能将这些物体放入一个背包,使背包的重量等于一个给定的值. 背包算法为第一个推广的公开密钥加密算法. 虽然后来发现这个算法不安全,但仍值得研究,因为它表示了如何将NP完全问题用于公开密钥算法(好吧,这个我

STL六大组件之——算法小小小小的解析

参考自侯捷的<stl源码剖析> stl算法主要分为非可变序列算法(指不直接修改其所操作的容器内容的算法),可变序列算法(指可以修改它们所操作的容器内容的算法),排序算法(包括对序列进行排序和合并的算法.搜索算法以及有序序列上的集合操作),数值算法(对容器内容进行数值计算). 1.非可变序列算法 stl中的非可变序列算法有:for_each(), find(), find_if(), adjacent_find(), find_first_of(), count(), count_if(), m

算法概念、大O记号

算法定义:基于特定的计算类型,旨在解决某一信息处理问题而设计的一个指令序列算法需具备以下要素 输入与输出输入(input):对所求解问题特定实例的描述 输出(output):经计算和处理之后得到的信息,即针对输入问题实例的答案 确定性和可行性:算法应可描述为由若干语义明确的基本操作组成的指令序列,且每一基本操作在对应的计算模型中均可兑现. 有穷性:任意算法都应在执行有限次基本操作之后终止并给出输出 正确性:算法所给的输出应该能够符合由问题本身在事先确定的条件 鲁棒性:例如处理算法输入的退化 重用

algorithm之不变序列操作

概述:不变序列算法,参见http://www.cplusplus.com/reference/algorithm/ /* std::for_each template <class InputIterator, class Function> Function for_each (InputIterator first, InputIterator last, Function fn); Apply function to range Applies function fn to each o

[6] 算法路 - 双向冒泡排序的Shaker

Shaker序列 –算法 1. 气泡排序的双向进行,先让气泡排序由左向右进行.再来让气泡排序由右往左进行,如此完毕一次排序的动作 2. 使用left与right两个旗标来记录左右两端已排序的元素位置. 一个排序的样例例如以下所看到的: 排序前:45 19 77 81 13 28 18 1977 11 往右排序:19 45 77 13 28 18 19 7711 [81] 向左排序:[11] 19 45 77 13 28 1819 77 [81] 往右排序:[11] 19 45 13 28 18

LMS算法去噪

LMS在语音增强中具备广泛的应用,是最为常见的算法之一,该算法也是很多更为复杂算法的理论基础或 组成部分,例如阵列语音增强中的重要方法--GSC(广义旁瓣抵消).LMS算法由最初的版本延伸出来许多变种结构,例如归一化LMS,变步长LMS等等.这些都是对LMS的迭代部分进行了一定的优化所得. 最近又看起了GSC的实现,以前写的程序又重新看了一遍,差不多又巩固了一遍,希望以后自己能够不要忘记了····我这个破记性,有时候真是很无奈! 首先是理论部分推导,在此不详述,简要给出流程: 自适应线性组合器及