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

Posted chenguang9239

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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]; // f[i] 代表以i下标对应元素结尾的最长上升子序列的长度
        String[] res = new String[len];
f[0] = 1;
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]; } } } // 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;
          end = 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

 

以上是关于LIS LCS 最长上升子序列 最长公共子序列 ...的主要内容,如果未能解决你的问题,请参考以下文章

刷题之最长公共/上升子序列问题

经典DP问题之最长上升子序列和最长公共子序列

最长公共上升子序列 (LIS+LCS+记录)

最长上升子序列 CSU - 1047 ( LIS LCS )

LCIS-最长公共上升子序列

[Mdp] lc1035. 不相交的线(LCS+LIS+重点知识理解)