LIS LCS 最长上升子序列 最长公共子序列 ...

最长上升子序列,问题定义:http://blog.csdn.net/chenwenshi/article/details/6027086

代码:

    public static void getData( char[] L )
    {
        int len = L.length;
        int[] f = new int[len];
        String[] res = new String[len];
        for( int i = 1; i < len; i++ )
        {
            f[i] = 1;
            res[i] = "" + L[i];
            for( int j = 0; j < i; j++ )
            {
                if( (L[j] - ‘0‘) < (L[i]-‘0‘) && f[j] + 1 > f[i] )
                {
                    f[i] = f[j] + 1;
                    res[i] = res[j] + " " + L[i];
                }
            }
            /* 下标连续递增子序列
            if( (L[i-1] - ‘0‘) == (L[i]-‘0‘) - 1 )
            {
                f[i] = f[i-1] + 1;
                res[i] = res[i-1] + " " + L[i];
            }
            /**/
        }
//        System.out.println( f[ len - 1 ]);
        int max = f[0];
        int maxK = 0;
        for( int k = 1; k < len; k++ )
        {
            if( f[k] > max )
            {
                max = f[k];
                maxK = k;
            }
        }
        System.out.println( f[ maxK ]);
        for( int k = 1; k < len; k++ )
        {
            if( f[k] == max )
            {
                System.out.println( res[k] );
            }
        }
    }

最大和子序列(最大和连续子序列)。MaxSum[i] 表示以i结尾的有最大和的连续子序列之和。MaxSum[i] = Max{ MaxSum[i-1] + A[i], A[i]}; 以下代码没有设置数组MaxSum[]。

题目描述:http://blog.csdn.net/hs794502825/article/details/7956730

    public static void getMax( String[] L )
    {
        int thisSum = 0, maxSum = 0;
        int begin=0,end = 0;
        int max = 0;

        String[] res = new String[L.length];
        res[0] = "" + L[0];
        for( int j = 1; j < L.length; j++ )
        {
            thisSum += Integer.parseInt( L[j] );
            if( thisSum > maxSum )
            {
                maxSum = thisSum;
                max = j;
            }
            if( thisSum < 0 )
            {
                thisSum = 0;
                begin = j+1;
            }
            res[j] = res[j-1]  + " " + L[j];
            end = j;
        }

        System.out.println( maxSum );        

        for( int k = begin; k <= end; k++ )
        {
            System.out.print( L[k] + " " );
        }

    }

L1与L2的最长公共子序列:

    public static void getLCS( char[] x, char[] y )
    {
        int m = x.length;
        int n = y.length;
        int[][] c = new int[m+1][n+1];
        int[][] b = new int[m+1][n+1];
        for( int row = 0; row < m; row ++ )
        {
            int i = row + 1;
            for( int col = 0; col < n; col ++ )
            {
                int j = col + 1;
                if( x[row] == y[col] )
                {
                    c[i][j] = c[i-1][j-1] + 1;
                    b[i][j] = 0;
                }
                else if( c[i-1][j] > c[i][j-1] )
                {
                    c[i][j] = c[i-1][j];
                    b[i][j] = 1;
                }
                else if( c[i-1][j] < c[i][j-1] )
                {
                    c[i][j] = c[i][j-1];
                    b[i][j] = 2;
                }
                else
                {
                    c[i][j] = c[i][j-1];
                    b[i][j] = 3;
                }
            }
        }

        int i = m;
        int j = n;
        Stack< Character > stack = new Stack< Character >();
        while( (i != 0) && ( j != 0) )
        {
            if( b[i][j] == 0 )
            {
                //System.out.println( x[m] );
                stack.push(x[i-1]);
                i -= 1;
                j -= 1;
            }
            else if( b[i][j] == 1 )
            {
                i -= 1;
            }
            else
            {
                 j -= 1;
            }
        }
        while( !stack.isEmpty() )
        {
            System.out.print( stack.pop() );
        }
    }    
public static void main(String[] args) {
        // TODO Auto-generated method stub
        String a = "abcdeabcdefg";
        String b = "acdeafdc";
        getLCS( a.toCharArray(), b.toCharArray() );
    }

装信封问题:

N个信封,给出宽、高。小信封装在大信封里,求这些信封最多能嵌套的层数。

第一行为N,接下来N行每行两个整数,分别表示宽与高。

4

5 4

6 4

6 7

2 3

这个问题可以转化为最长递增子序列问题。首先按照宽度将N个信封由小到大排序,当宽度相同时,按高度从大到小排序:2 3, 5 4, 6 7, 6 4。防止了当宽度相同时,高度小的嵌套进高度大的信封。代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool cmp( const pair<int,int>& x, const pair<int,int>& y )
{
    return x.first != y.first ? x.first < y.first : x.second > y.second;
}
int findMax( vector< pair< int, int > > e )
{
    int n = e.size();
    if( n == 0 )
    {
        return 0;
    }

    sort( e.begin(), e.end(), cmp );

    vector<int> dp(n,1);
    for( int i = 1; i < n; i++ )
    {
        //dp[i] = 1;
        for( int j = 0; j < i; j++ )
        {
            if( ( dp[i] < dp[j]+1 ) && ( e[i].second > e[j].second ) && ( e[i].first > e[j].first ) )
            {
                dp[i] = dp[j]+1;
            }
        }
    }
    int maxv = 0;
    for( int i = 0 ; i < n; i++ )
    {
        if( dp[i] > maxv )
        {
            maxv = dp[i];
        }
    }

    // O(nlogn):
    // http://blog.csdn.net/shuangde800/article/details/7474903
    // http://www.jiuzhang.com/solutions/russian-doll-envelopes/
    // 当有多个子序列s1,s2,,,内元素数为均为k个时,选择si,si的第k个元素比其他s1,s2...的第k个元素都小
    // 数组d[k]即表示,当上升子序列元素个数为k时,si中第k个元素的值
    vector< int > d( n+1, 0 );
    int len = 0;
    for( int k = 0; k < n; k++ )
    {
        if( d[len] < e[k].second )
        {
            d[++len] = e[k].second;
        }
        else
        {
            //需要找到比d[mid]大的第一个位置,即插入数据的位置

            //d数组中的元素不会重复,用二分插入排序查找插入位置就可以
            //index: 1 2 3 4 5
            //value: a a a a b
            //区别:
            //查找下界的二分查找,查找a时返回第一个a的位置1
            //二分插入排序查找插入位置,插入a时,返回最后一个a的下一个位置6

            //stl中binary_search函数功能是查看某一值在一个已经排好序的序列中是否存在,
            //当存在时返回true,否则返回false

            //如果所要查找的元素只有一个,那么lower_bound()返回了这个元素的地址,不是下标
            //如果相同元素出现了多次,那么lower_bound()找到了第一个所找元素的地址
            //即:返回第一个大于或等于val的元素的地址
            //upper_bound返回第一个大于val元素的地址
            //算法竞赛入门 p.125

            int left=1, right=len, mid, j = -1;
            while( left <= right )
            {
                mid = ( left + right )/2;
                //当 d[mid] 与 e[k].second(待插入数值)相等时,left也要置为mid+1,
                //这也保证也二分插入排序是稳定的
                if( d[mid] > e[k].second )
                {
                    right = mid - 1;
                }
                else
                {
                    left = mid + 1;
                }
            }

            // left; 待插入数据位置,第一个待插入数字大的位置
            d[ left ] = e[k].second;
        }
    }
    cout << len << "+++++++" << endl;

    return maxv;
}

int main()
{
    vector< pair< int, int > > e;
    int n;
    cin >> n;
    int a, b;
    for( int i = 0; i < n; i++ )
    {
        cin >> a >> b;
        e.push_back( make_pair<int,int>( a, b ) );
    }

    cout << findMax( e );
    return 0;
}

在O(nlogn)的实现中,还引申出了二分查找的上下界问题。

另外,当要求最长不下降子序列时,这篇文章给出了很好的分析:http://www.cnblogs.com/itlqs/p/5743114.html

时间: 2024-12-28 00:58:10

LIS LCS 最长上升子序列 最长公共子序列 ...的相关文章

求最长公共子序列长度

poj 1458  Common Subsequence http://poj.org/problem?id=1458 问题分析: 这个题是求两个序列的最长公共最序列长度,在这里要弄清楚两个问题 1:本题中所有的子序列并没有要求是连续子序列,所以在求最长子序列的时候不连续是允许的 2:哪部分子序列才是最长的 对于给定的 X = < x1, x2, ..., xm > 和 Z = < z1, z2, ..., zk > ,X序列与Z的每一个子序列都含有公共子序列(最小为0),同理,Z

公共子序列与公共子串问题

1.公共子序列问题 网上有很多关于公共子序列问题,说的大同小异,看了很多不明白,很多都是晦涩难懂,这里分享一个连接,个人觉得讲述的比较明白,易懂. http://blog.csdn.net/v_july_v/article/details/6695482 我这里也简单的把自己的理解说一下,求公共子序列问题是一个非常常见的问题,最差的方法就是暴力匹配,暴力匹配算法第一步求去短字符串的所有序列组合,然后从长到短一个一个的去匹配时候有公共序列相同,即使使用了这样的剪枝,该算法效率任然很低. 比较受人青

最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)

最长公共子序列(LCS) [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij=yj.例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列. 考虑最长公共子序列问题如何分解成

算法设计 - LCS 最长公共子序列&amp;&amp;最长公共子串 &amp;&amp;LIS 最长递增子序列

出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的最长公共子串方法.最长公共子串用动态规划可实现O(n^2)的时间复杂度,O(n^2)的空间复杂度:还可以进一步优化,用后缀数组的方法优化成线性时间O(nlogn):空间也可以用其他方法优化成线性.3.LIS(最长递增序列)DP方法可实现O(n^2)的时间复杂度,进一步优化最佳可达到O(nlogn)

LIS(最长递增子序列)和LCS(最长公共子序列)的总结

最长公共子序列(LCS):O(n^2) 两个for循环让两个字符串按位的匹配:i in range(1, len1) j in range(1, len2) s1[i - 1] == s2[j - 1], dp[i][j] = dp[i - 1][j -1] + 1; s1[i - 1] != s2[j - 1], dp[i][j] = max (dp[i - 1][j], dp[i][j - 1]); 初始化:dp[i][0] = dp[0][j] = 0; 伪代码: dp[maxn1][ma

LCS求最长公共子序列(DP)

动态规划并不是一种算法,而是一种解决问题的思路.典型的动态规划问题,如最长公共子序列(LCS),最长单调子序列(LIS)等. 动态规划分为四个步骤: 1.判断问题是否具有最优子结构 这里以LCS为例,X={x1,x2,...,xi}:Y={y1,y2,...,yj}.最长公共子序列Z={z1,z2,...,zk}: ①如果xi=yj,那么zk=xi=yj,且Zk-1是序列Xi-1和Yj-1的LCS: ②如果xi≠yj,那么zk≠xi:且Zk是序列Xi-1和Yj的LCS: ③如果xi≠yj,那么z

对最长公共子序列(LCS)等一系列DP问题的研究

LIS问题: 设\(f[i]\)为以\(a[i]\)结尾的最长上升子序列长度,有: \[f[i]=f[j]+1(j<i&&a[j]<a[i])\] 可以用树状数组优化至\(O(nlogn)\) 基于排列的LCS问题(\(a,b\)均为排列,即一个元素不会出现多次): 设\(pos_i\)为\(a_i\)在\(b\)中出现的位置,即\(a_i=b_pos_i\). \(a\)的一个子序列\(a_p_1,a_p_2,...,a_p_m\)是\(a,b\)的公共子序列等价于\(pos

最长公共子序列(LCS)问题

最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common Subsequence,LCS)的区别为:子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而获得新的序列:也就是说,子串中字符的位置必须是连续的,子序列则可以不必连续. 1.序列str1和序列str2 ·长度分别为m和n: ·创建1个二维数组L[m.n]: ·初始化L数组内容为0 ·m和n分别从0开始,m++,n++循环: - 如果str1[m] ==

hdu 1159 Common Subsequence(dp 最长公共子序列问题LCS)

最长公共子序列问题(LCS,Longerst Common Subsequence). s1s2……si+1和t1t2……tj+1的公共子序列可能是: ①当si+1=tj+1时,在s1s2……si+1和t1t2……tj+1的公共子序列末尾追加一个. ②s1s2……si+1和t1t2……tj的公共子序列 ③s1s2……si和t1t2……tj+1的公共子序列 所以易得到递推关系dp[i+1][j+1]=  max{ dp[i][j]+1 , dp[i][j+1] , dp[i+1][j]) }