标签:
给出一个数n,然后给出n个数,求n个数的最长单调子序列。如:
n = 7
7 1 5 2 9 3 6
方法一:DP
dp[i] 表示元素值不超过i时的最长单调序列。时间复杂度为O(n^2)则可以这样:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 100000
int a[N];
int dp[N];
int main()
{
//freopen("in.txt", "r", stdin);
int n;
while(~scanf("%d", &n))
{
int i, j;
for(i=0; i<n; i++){
scanf("%d", &a[i]);
dp[i] = 1;
}
int max = -(1<<30);
for(i=0; i<n; i++){
for(j=0; j<i; j++){
if(a[i] > a[j] && dp[i] < dp[j] + 1)
dp[i] = dp[j] + 1;
}
if(dp[i] > max) max = dp[i];
}
printf("%d\n", max);
}
}
其中c[i] 表示长度为i的单调递增子序列的最后一个元素。在遍历过程c[i]取值可能有多个,则取值最小的一个。这样c数组中的元素就会是递增的。所以可以用二分查找。
比如之前的例子:
n = 7
7 1 5 2 9 3 6
a[] 0 1 2 3 4 5 6
核心过程:
对c数组初始化为一个不可能出现的数。
先令len = 1;c[len] = a[0];
之后在c数组中遍历查找a[i] (1 < i < n),如果a[i] > c[len];就在c数组末尾添加,即是c[++len] = a[i];如果找到了a[i],就不做什么,如找不到,就把c数组中第一个比a[i] 大的数替换成a[i],最后,c数组的长度len就是a数组的最长单调子序列长度!
0 1 2 3 4 5 6 7 (c数组下标)
a[0] -> c -1 7
a[1] -> c -1 1
a[2] -> c -1 1 5
a[3] -> c -1 1 2
a[4] -> c -1 1 2 9
a[5] -> c -1 1 2 3
a[6] -> c -1 1 2 3 6
所以len = 4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 100010
int c[N];
int ans;
void bsearch(int *A, int l, int r, int key)
{
if(key > A[r]){
ans++;
A[ans] = key;
}
int mid;
while(l <= r)
{
mid = l + (r - l) / 2;
if(A[mid] == key) return;
else if(A[mid] > key) r = mid - 1;
else l = mid + 1;
}
A[l] = key;
}
int main()
{
//freopen("in.txt", "r", stdin);
int n, a;
while(~scanf("%d", &n))
{
ans = 1;
memset(c, 0, sizeof(c));
int i, j;
scanf("%d", &a);
c[1] = a;
for(i=1; i<n; i++){
scanf("%d", &a);
bsearch(c, 1, ans, a);
}
printf("%d\n", ans);
}
return 0;
}
标签:
原文地址:http://blog.csdn.net/u013351484/article/details/44303361