最长上升子串

n^2的解法

对于a[i]来说,j in 0..i-1,如果a[i]>a[j],则dp[i] = dp[j]+1,否则dp[i]至少为1

For i in 0..n
  For j in 0..i-1
    If(a[i] > a[j]) dp[i] = max(dp[i],dp[j]+1);
  dp[i] = max(1,dp[i]);

nlogn解法

http://www.ahathinking.com/archives/117.html

目的:我们期望在前i个元素中的所有长度为len的递增子序列中找到这样一个序列,它的最大元素比arr[i+1]小,而且长度要尽量的长,如此,我们只需记录len长度的递增子序列中最大元素的最小值就能使得将来的递增子序列尽量地长。

方法:维护一个数组MaxV[i],记录长度为i的递增子序列中最大元素的最小值,并对于数组中的每个元素考察其是哪个子序列的最大元素,二分更新MaxV数组,最终i的值便是最长递增子序列的长度。这个方法真是太巧妙了,妙不可言。

MaxV[ ]必然是一个递增的数组,记录长度为i的序列中最大的那个数(也就是最后的那个数)为多少

对于a[] = { 1,-1, 2,-3,4,-5, 6,7}  这个例子来说,

i为1时,一开始MaxV[0] = 1;

i为2时,然后MaxV[0] = -1,因为 -1 < 1,用-1来替换1可以取得更好的结果

i为3时,MaxV[1] = 2,因为 2 > -1,所以 2可以接在-1的后面组成一个更长的数组

i为4时,MaxV[0] = -3,因为 -3 < -1 ,用-3来替代-1可以取得更好的效果。

。。。。。。。。

所以要是能够快速在MaxV[]中刚好比a[i]大的数k,然后用a[i]来替换k就可以取得更好的效果,如果MaxV[]中所以的数都比a[i]小,那么说明可以得到一个更长的序列,就把MaxV[++len] = a[i]

for i in 0..n do{    if(a[i] > MaxV[len-1]) /* 大于最大的自然无需查找,否则二分查其位置 */
      MaxV[len++] = a[i];
    else
    {
       int pos = BinSearch(MaxV,len,a[i]);//相当于lower_bound, 返回     MaxV[i]中刚刚大于x的那个元素的下标
       MaxV[pos] = a[i];
    }}

以下是几种详细的代码

#include <iostream>
using namespace std;
/* 最长递增子序列 LIS
 * 设数组长度不超过 30
 * DP + BinarySearch
*/
int MaxV[30]; /* 存储长度i+1(len)的子序列最大元素的最小值 */
int len;      /* 存储子序列的最大长度 即MaxV当前的下标*/
/* 返回MaxV[i]中刚刚大于x的那个元素的下标 */
int BinSearch(int * MaxV, int size, int x)
{
    int left = 0, right = size-1;
    while(left <= right)
    {
        int mid = (left + right) / 2;
        if(MaxV[mid] <= x)
        {
            left = mid + 1;
        }        else
        {
            right = mid - 1;
        }
    }
    return left;
}
int LIS(int * arr, int size)
{
    MaxV[0] = arr[0]; /* 初始化 */
    len = 1;
    for(int i = 1; i < size; ++i) /* 寻找arr[i]属于哪个长度LIS的最大元素 */
    {
        if(arr[i] > MaxV[len-1]) /* 大于最大的自然无需查找,否则二分查其位置 */
        {
            MaxV[len++] = arr[i];
        }        else
        {
           int pos = BinSearch(MaxV,len,arr[i]);//相当于lower_bound, 返回MaxV[i]中刚刚大于x的那个元素的下标
           MaxV[pos] = arr[i];
        }
    }
    return len;
}

void main()
{
    int arr[] = {1,-1,2,-3,4,-5,6,-7};
    /* 计算LIS长度 */
    printf("%d\n",LIS(arr,sizeof(arr)/sizeof(int)));
}

使用lower_bound函数

Foj   1438实在是太恶心了。。。。

#include<stdio.h>

#include<stdlib.h>

#include<iostream>

#include<string.h>

#include<queue>

#include<algorithm>

using namespace std;

#define LL __int64

#define M 220100

const int INF = 2139062143;

const int mod = 1000000007;

int __ = 0;

#define BIAOJI printf("yes%d\n",++__);

int f[M] = {0};

int a[M] = {0},n,nb = 0;

int b[M] = {0};

int main()

{

    freopen("in.txt","r",stdin);

    while(cin>>n)

    {

    memset(f,0,sizeof(f));

    memset(a,0,sizeof(a));

    memset(b,0,sizeof(b));

    for(int i = 1;i<=n;++i)scanf("%d",&a[i]);

    f[1] = 1;

    b[1] = a[1];

    nb = 1;

    for(int i = 2;i<=n;++i)

    {

        int kk = lower_bound(b+1,b+nb+1,a[i]) - b;

        if(kk == nb+1) ++nb;

        b[kk] = a[i];

        f[i] = kk;

        //PP();

    }

    int ret = 0;

    for(int i = 1;i<=n;++i) ret = max(ret,f[i]);

    cout<<ret<<endl;

    }

    return 0;

}

/*

int main()

{

    freopen("in.txt","r",stdin);

    while(cin>>n)

    {

        int ans = 0;

    memset(a,0,sizeof(a));

    for(int i = 0;i<n;++i)scanf("%d",&a[i]);

    int *b=new int [n+1];

         b[ans=0]=-0x7fffffff;

         for(int i=0;i<n;i++){

                   int k=lower_bound(b,b+ans+1,a[i])-b;

//upper_bound for Longest Non Descending Sub Sequence;

                   if (k>ans) b[++ans]=a[i];

        else if (b[k]>a[i]) b[k]=a[i];

         }

    cout<<ans<<endl;

    }

    return 0;

}

*/
时间: 2024-08-10 02:08:41

最长上升子串的相关文章

最长公共子串

(连续) - 阿里笔试[分析+编码] 题目描述:给定一个query和一个text,均由小写字母组成.要求在text中找出以同样的顺序连续出现在query中的最长连续字母序列的长度.例如,query为“acbac”,text为“acaccbabb”,那么text中的“cba”为最长的连续出现在query中的字母序列,因此,返回结果应该为其长度3.请注意程序效率. [思路]用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0.然后求出对角线最长的1序列,其对应的位置

一天一道算法题(5)---最长公共子串

题目 给定两个字符串str1和str2,返回两个字符串的最长公共子串.例如:str1="1AB2345CD",str2="12345EF",公共子串是"2345" 解析 最长公共子串和最长公共子序列的区别是,子串是连续的,子序列是不连续的. 首先还是要生成动态规划表.生成大小为M*N的矩阵dp.dp[i][j]的含义是,在必须把str1[i]和str2[j]当作公共子串最后一个字符的情况下,公共子串最长能有多长.比如,str1="A12

3160 最长公共子串

3160 最长公共子串 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 题目描述 Description 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入描述 Input Description 读入两个字符串 输出描述 Output Description 输出最长公共子串的长度 样例输入 Sample Input yeshowmuchiloveyoumydearmotherreallyicannotbelieveityeaphow

[URAL-1517][求两个字符串的最长公共子串]

Freedom of Choice URAL - 1517 Background Before Albanian people could bear with the freedom of speech (this story is fully described in the problem "Freedom of speech"), another freedom - the freedom of choice - came down on them. In the near fu

POJ 2774 最长公共子串

对于最长公共子串,n*m的递推显然无法通过本题. 本题是后缀数组的一个基础应用,字符串的子串可以视作后缀的前缀. 我们在两个串间插入一个不在字符集的字符如'#'作为连接,这样做的目的是为了防止两个后缀的最长公共前缀跨过第一个字符串的末尾. 扫描Height数组,如果排名为i的字符串与排名为i-1的字符串来源于原来的2个串,则更新答案最大值. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm>

字符串中连续出现最多的子串 &amp; 字符串中最长重复子串

字符串中连续出现最多的子串 & 字符串中最长重复子串 字符串中连续出现最多的子串 & 字符串中最长重复子串,这两个问题都可以用后缀数组来表示,至于后缀数组可以参考编程珠玑P156:后缀数组就是定义一个数组指针,分别指向字符串中的对应位置,如下: a b c a b c a b c d e .substr[0] b c a b c a b c d e ....substr[1] c a b c a b c d e .......substr[2] a b c a b c d e ......

【wikioi】3160 最长公共子串(后缀自动机)

http://codevs.cn/problem/3160/ sam的裸题...(之前写了spoj上另一题sam的题目,但是spoj被卡评测现在还没评测完QAQ打算写那题题解时再来详细介绍sam的....那就再等等吧. 求两个串的lcs话,就是先建立a串的sam,然后用b的字串去匹配a中. 因为sam中每个状态的len对应最长子串,因此自动机不断trans匹配时,如果没找到下一个点,那么在parent树的祖先中找是否还有子串可以更新(因为祖先的max比这个节点小,且都包含当前状态的right,所

字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

Long Long Message Problem's Link:http://poj.org/problem?id=2774 Mean: 求两个字符串的最长公共子串的长度. analyse: 前面在学习后缀数组的时候已经做过一遍了,但是现在主攻字符串hash,再用字符串hash写一遍. 这题的思路是这样的: 1)取较短的串的长度作为high,然后二分答案(每次判断长度为mid=(low+high)>>1是否存在,如果存在就增加下界:不存在就缩小上界): 2)主要是对答案的判断(judge函数

最长公共子串和最长公共序列

1. 最长公共子串 注意子串是连续的.有下列动态转移方程 c[i][j] = c[i-1][j-1] + 1   when X[i] = Y[j] c[i][j] = 0   when X[i] != Y[j] 1 c[100][100]; 2 3 int LCS(char x[], int len_x, char y[], int len_y){ 4 5 int max_len = 0; 6 7 for(int i =0; i < len_x ; i++){ 8 for(int j = 0;

HDU 1403 Longest Common Substring(后缀数组,最长公共子串)

hdu题目 poj题目 参考了 罗穗骞的论文<后缀数组——处理字符串的有力工具> 题意:求两个序列的最长公共子串 思路:后缀数组经典题目之一(模版题) //后缀数组sa:将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置.简单的记忆就是“排第几的是谁”. //名次数组rank:rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次.则 若 sa[i]=j,则 rank[j]=i.简单的记忆就是“你排第几”