您的位置:首页 > 其它

最长上升子序列问题LIS

2016-08-09 20:45 267 查看
问题描述(poj2533):对于给定的n个整数A1, A2…An, 从左到右的顺序选择尽可能多的数,组成一个上升子序列。(上升子序列可以理解为:删除0个或多个数, 其他数的顺序不变, 例如1, 6, 2, 3, 7, 5, 可以选出上升子序列1, 2, 3, 5 也可以选出 1, 6, 7)

poj2533 : 求最长上升子序列的长度

法一:通过DP记忆化搜索求解问题,时间复杂度为O(n^2)

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include <algorithm>
using namespace std;

int n, m, i, j, mx;
const int maxn = 1010;
int a[maxn], d[maxn];

//记忆化搜索
//状态:d[i]:第i个数的最长子序列的长度
//状态转移为d[i] = max(d[i], d[j] + 1);
int main()
{
while(~scanf("%d",&n)){              //共有n个数
for(i = 0; i < n;i++)           //录入n个数保存在数组a[]中
scanf("%d",&a[i]);
for (i = 0; i < n; i++)
{
d[i] = 1;                              //初始化数组d[]为1,
for(j = 0;j < i;j++)
if(a[j] < a[i])
d[i] = max(d[i], d[j] + 1); //第i个数的最长子序列长度 等于 比 第i个数小 的 数的最长子序列加1
}
mx = 0;
for(i = 0;i < n;i++)
mx = max (mx ,d[i]);
printf("%d\n",mx);
}
return 0;
}


法二:用DP二分搜索解决问题降低时间复杂度,该方法的时间复杂度为O(nlogn)

实现:开一个栈,每次取栈顶元素top和读到的元素temp做比较,如果temp > top 则将temp入栈;如果temp < top则二分查找栈中的比temp大的第1个数,并用temp替换它。 最长序列长度即为栈的大小top。

举例:原序列为1,5,8,3,6,7

栈为1,5,8,此时读到3,用3替换5,得到1,3,8; 再读6,用6替换8,得到1,3,6;再读7,得到最终栈为1,3,6,7。最长递增子序列为长度4。

如果想要输出最长有序子数列的话,可以在法二的基础上稍作改动。

用一个b【i】记录第i个元素在队列中的位置,然后逆向寻找,依次输出。

//二分搜索
#include <iostream>
#define SIZE 1001

using namespace std;

int main()
{
int i, j, n, top, temp;
int stack[SIZE];
cin >> n;

top = 0;
stack[0] = -1;//令栈顶元素为-1
for (i = 0; i < n; i++)
{
cin >> temp;
/* 比栈顶元素大数就入栈 */
if (temp > stack[top])
{
stack[++top] = temp;
}
else
{
int low = 1, high = top;
int mid;
/* 二分检索栈中比temp大的第一个数 */
while (low <= high)
{
mid = (low + high) / 2;
if (temp > stack[mid])
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
/* 用temp替换 */
stack[low] = temp;
}
}

/* 最长序列数就是栈的大小 */
cout << top << endl;

//system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj dp