最长上升子序列,问题定义: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 = ; i < len; i++ )
{
f[i] = ;
res[i] = "" + L[i];
for( int j = ; j < i; j++ )
{
if( (L[j] - '') < (L[i]-'') && f[j] + > f[i] )
{
f[i] = f[j] + ;
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[];
int maxK = ;
for( int k = ; k < len; k++ )
{
if( f[k] > max )
{
max = f[k];
maxK = k;
}
}
System.out.println( f[ maxK ]);
for( int k = ; 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 == )
{
return ;
} sort( e.begin(), e.end(), cmp ); vector<int> dp(n,);
for( int i = ; i < n; i++ )
{
//dp[i] = 1;
for( int j = ; j < i; j++ )
{
if( ( dp[i] < dp[j]+ ) && ( e[i].second > e[j].second ) && ( e[i].first > e[j].first ) )
{
dp[i] = dp[j]+;
}
}
}
int maxv = ;
for( int i = ; 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+, );
int len = ;
for( int k = ; 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=, right=len, mid, j = -;
while( left <= right )
{
mid = ( left + right )/;
//当 d[mid] 与 e[k].second(待插入数值)相等时,left也要置为mid+1,
//这也保证也二分插入排序是稳定的
if( d[mid] > e[k].second )
{
right = mid - ;
}
else
{
left = mid + ;
}
} // 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 = ; i < n; i++ )
{
cin >> a >> b;
e.push_back( make_pair<int,int>( a, b ) );
} cout << findMax( e );
return ;
}
在O(nlogn)的实现中,还引申出了二分查找的上下界问题。
另外,当要求最长不下降子序列时,这篇文章给出了很好的分析:http://www.cnblogs.com/itlqs/p/5743114.html