最长上升子序列,问题定义: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