给出一段整数序列 , 要求出这个序列的最长递增子序列 。
方法一:
我们可以利用背包状态转移的思想 , 从后先前分析 , 我们先只考虑前 i-1 个元素中的最长递增子序列 , 当求前 i 个元素的最长递增序列时 , 我们只需要确定第 i 个元素可以放在前 i-1 个元素中哪些元素的后面 , 则 i 元素就能跟该元素构成一个新的序列。即:
k <= i-1 ;
xy[i] > xy[k] , 则 i 元素就能放在 k 元素的后面 , 这样就构成了一个新的递增序列
代码:
int main()
{
int xy[100010] , n;
int dp[100010];
while(scanf("%lld" , &n) != EOF)
{
int i , j;
for(i = 1; i <= n; i++)
cin>>xy[i];
//memset(dp , 0 , sizeof(dp));
dp[1] = 1;
for(i = 2; i <= n; i++)
{
dp[i] = 1;
for(j = 1; j < i; j++)//顺序查找
{
if(xy[j] < xy[i] && dp[i] < (dp[j]+1))
dp[i] = dp[j]+1;
}
}//时间复杂度为:n*n
int maxsum = 0;
for(i = 1; i <= n; i++)
if(dp[i] > maxsum)
maxsum = dp[i];
cout<<maxsum<<endl;
}
return 0;
}
方法二:(dp + 二分查找)
对于方法一 , 我们可以分析出其时间复杂度为:n*n , 这复杂度太高了 , 所以我们要在改善这个算法。
在方法一中我们是在用顺序查找来查找xy[i]在0~i-1中的位置 , 因此我们可以在这里下手 , 把顺序查找该为二分查找 , 则时间复杂度变为了:n*lgn;
这个方法的原理:
首先我们知道 , 对于每一个长度(递增序列中的元素数量)的递增序列 , 我们只需要记录该序列的最后的一个元素就行了 , 我们可以用一个数组 c 来储存 ,则c[1]就储存只有一个元素的递增序列中的最大那个数(也就是最后面那个数) , c[2] 就储存只有2个元素的递增序列中的最大那个数.........
因此我们就得到了一个有序的数组 c , 那么当我们确定 xy[i] 这个元素的最长递增序列时 , 我们只需要在 c 中找到最小的大于xy[i]的元素的位置 , 这个位置就是xy[i]的最长递增序列。
所以 , 我们需要长期来维护数组c
代码:
#include
using namespace std;
long long int xy[100100];
long long int c[100100];
long long int find(long long int n , long long int x)
{
long long int left = 1 , right = n ;
long long int mid;
while(left <= right)
{
mid = (right+left)/2;
if(c[mid] < x) left = mid + 1;
// 这里要注意 , 因为是要求大于 x 的元素的位子 , 所以这里不能加等于
else right = mid - 1;
}
return left;
}
int main()
{
long long int n;
while(scanf("%lld" , &n) != EOF)
{
long long int i , j;
for(i = 1; i <= n; i++)
cin>>xy[i];
c[0] = -1;
c[1] = xy[1];
long long int len = 1;
for(i = 2; i <= n; i++)
{
j = find(len , xy[i]);
c[j] = xy[i]; //维护数组c
if(j > len)
len = j;
}
cout<<len<<endl;
}
return 0;
}
方法一:
我们可以利用背包状态转移的思想 , 从后先前分析 , 我们先只考虑前 i-1 个元素中的最长递增子序列 , 当求前 i 个元素的最长递增序列时 , 我们只需要确定第 i 个元素可以放在前 i-1 个元素中哪些元素的后面 , 则 i 元素就能跟该元素构成一个新的序列。即:
k <= i-1 ;
xy[i] > xy[k] , 则 i 元素就能放在 k 元素的后面 , 这样就构成了一个新的递增序列
代码:
int main()
{
}
方法二:(dp + 二分查找)
对于方法一 , 我们可以分析出其时间复杂度为:n*n , 这复杂度太高了 , 所以我们要在改善这个算法。
在方法一中我们是在用顺序查找来查找xy[i]在0~i-1中的位置 , 因此我们可以在这里下手 , 把顺序查找该为二分查找 , 则时间复杂度变为了:n*lgn;
这个方法的原理:
首先我们知道 , 对于每一个长度(递增序列中的元素数量)的递增序列 , 我们只需要记录该序列的最后的一个元素就行了 , 我们可以用一个数组 c 来储存 ,则c[1]就储存只有一个元素的递增序列中的最大那个数(也就是最后面那个数) , c[2] 就储存只有2个元素的递增序列中的最大那个数.........
因此我们就得到了一个有序的数组 c , 那么当我们确定 xy[i] 这个元素的最长递增序列时 , 我们只需要在 c 中找到最小的大于xy[i]的元素的位置 , 这个位置就是xy[i]的最长递增序列。
所以 , 我们需要长期来维护数组c
代码:
#include
using namespace std;
long long int xy[100100];
long long int c[100100];
long long int find(long long int n , long long int x)
{
}
int main()
{
}