• 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

  • 相关阅读:
    Win64 驱动内核编程-12.回调监控进线程创建和退出
    我的主站 SHARELIST -分享列表 (功能持续完善中 2019-11-24 版本0.3)
    Caddy-基于go的微型serve用来做反向代理和Gateway
    Docker Swarm删除节点
    Docker Swarm集群搭建
    Docker Machine-Windows
    Docker Compose
    Docker网络配置进阶
    Docker网络相关
    Docker数据管理
  • 原文地址:https://www.cnblogs.com/wangzhiyi/p/6690741.html
Copyright © 2020-2023  润新知