求一序列的最长递增子序列,救命啊

arnold8792 2004-06-24 01:20:10
比如1,3,2,4,6,5
最长递增的为:1246.....
长度为4
有什么好的办法求出来
...全文
999 32 打赏 收藏 转发到动态 举报
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
galois_godel 2004-07-12
  • 打赏
  • 举报
回复
比较简单的O(n^2)的做法
设f[i] 表示结尾元素为原序列中第i 个元素的最长单调递增序列的长度,动态规划的状态转移方程如下:
f[i]=max{f[j]+1:,0<j<i, && a[j]<a[i]};
最后所要求的结果就是{f[i]}中的最大值。

在这个做法的基础上:
我们引入一个辅助数组。设g[i] 表示到目前为止,所有长度为i的单调递增子序列中最后一个元素的最小值。易知,g[i]-1≤g[i](1≤i≤n)(可以用反证法来证明),
也就是说,{g[i]}是一个不下降序列。当到第i-1 个字符为止的{g[i]}已知时,f[i] 就等于在
{g[i]}中第一个大于或等于ai 的元素的位置。然后,我们要对{g[i]}进行更新。更新十分简单,只要令g[f[i]]=a[i] 就可以了。一开始,令g[i]=∞(1≤i≤n)。由于
每次查找位置的时间复杂度为O(log n),(因为g是不下降序列)而更新的时间复杂度为O(1),因此,这个算法总的时间复杂度就是O(nlog n),
galois_godel 2004-07-12
  • 打赏
  • 举报
回复
faint!
arnold8792 2004-07-12
  • 打赏
  • 举报
回复
看了大家这么多的算法,我提出了其中的两种,有理解错的地方请改正
1.原序列为src[n]
新分配temp[n]与answer[n][n],长度为n是最大值
从src中依次取出元素,在temp中查找,使得temp[y] < src[x] < temp[y+1] 边界问题在内.
则替换temp[y+1]为src[x],如src[x]比temp中任一元素大,则添加于末尾
在此过程后执行copy answer[y] to answer[y+1], add src[x] to answer[y+1]
这样最后一个answer[last]即为最优解
2.原序列为src[n]
新分配temp[n]与answer[n][n],长度为n是最大值
for(int i=0; i<n; i++)
for(int k=0; k<i; k++){
if(src[i]>src[k] && temp[i]<=temp[k]){
temp[i]=temp[k]+1;
copy answer[k] to answer[i], add src[i] to answer[i]
}
}
找出最长的answer[]数组,即为最优解
eion 2004-07-01
  • 打赏
  • 举报
回复
const int N = 20;
int max_inc_seq()
{
int A[N] = {....};
int B[N] = {-1};
int C[N] = {-1};
int max=0, max_idx = 0;
for (int i=1; i<N; i++) B[i] = C[i] = 0;
for (int i=0; i<N; i++) for (int j=i+1; j<N; j++)
if (A[j]>A[i] && B[i]+1>B[j])
B[j] = B[C[j]=i] + 1;
for (int i=0; i<N; i++) if (B[i] > max) max = B[max_idx=i];
int i=0;
for (i=max_idx; i!=C[i]; i=C[i])
printf("%3d <-- ", A[i]);
printf("%3d\n", A[i]);
}
eion 2004-07-01
  • 打赏
  • 举报
回复
错了,应该是关键路径的思想
eion 2004-07-01
  • 打赏
  • 举报
回复
拓扑排序就OK
SimonSui 2004-07-01
  • 打赏
  • 举报
回复
input[] 1,4,3,2,3;
max[] 1,2,2,2,3;
max[i] 即为input[0_(i-1)]这个子序列中能找出的最长递增子序列的长度,
但这种方法的复杂度是o(n^2)啊,而且要得到最优解,还得用什么办法找呢?

到这从最大的往回找3,3
然后在前面的max[]=2中找最小的2,2
再在前面的max[]=1中找最小的1,1
BlueAllRise 2004-06-30
  • 打赏
  • 举报
回复
我上面那个程序的数组 F[i] 表示,第i位前最长的最长递增子序列的长度...相应的F[N] 就是整个数列的最长递增子序列的长度...
A就是存整个数列...
BlueAllRise 2004-06-29
  • 打赏
  • 举报
回复
Dp就是动态规划...
cyj2008 2004-06-29
  • 打赏
  • 举报
回复
《算法分析与设计》(机械出版社)书上有这个算法,书上采用的是动态规划策略,自己去查资料。
arnold8792 2004-06-28
  • 打赏
  • 举报
回复
to shuibinlang(阿水)
你的方法是求一序列的最长连续递增子序列,而我的要求没有连续

BlueAllRise 2004-06-28
  • 打赏
  • 举报
回复
哦,你是不是还要把这些数找出来?再加个数组就可以了,上面的代码是Pascal的..
BlueAllRise 2004-06-28
  • 打赏
  • 举报
回复
这个东西很简单的,这个是基础阿,也是Dp入门的经典问题..
f:array [1..100] of integer; //
a:array [1..100] of integer;

f[1]:=1;
for i:=1 to n do
begin
for j:=1 to i-1 do
if (a[j]>=a[j])and(f[i]<=f[j]) then
f[i]:=f[j]+1;
end;

零时编的,没有用编译器,可能在细节上有点问题,但是总的思想是对的...
LeeMaRS 2004-06-27
  • 打赏
  • 举报
回复
楼上上的,你的算法根本是错误的啊。再帖一次反例:
1 0 2 0 3 0 4 0

注意,所求子序列不一定是连续的!
About2Rain 2004-06-27
  • 打赏
  • 举报
回复
楼上的,你说的那个我也知道啊
问题是你那个只能知道长度,但是无法输出序列啊
shuibinlang 2004-06-27
  • 打赏
  • 举报
回复
以下是目前最优的解法(国外专家几经修改后的结果,参看《编程珠玑》),大家何不学学?

复杂度O(n)
以下为伪码:
input: input[n]
len = 1
maxlen = 1
for i = [1,n)
if(input[i] > input[i-1])
++len
else
len = 1
maxlen = max(len, maxlen)
printf: maxlen
arnold8792 2004-06-26
  • 打赏
  • 举报
回复
这个复杂度不会低于o(nlgn)吧
有没有把最优解一并输出的方法
最好能给出伪码
privet 2004-06-26
  • 打赏
  • 举报
回复
写错了
设序列为a1,a2,...an,将序列升序排序后为b1,b2,...bn,
降序改为升序
privet 2004-06-26
  • 打赏
  • 举报
回复
设序列为a1,a2,...an,将序列降序排序后为b1,b2,...bn,
问题转化为求a1,a2,...an和b1,b2,...bn的最长公共子序列,
记两序列分别为A序列和B序列。
可采用递推如下:
1)建立二维数组c[n+1][n+1],
c[i][j]表示A序列的前i个元素构成的子序列Ai与Bi(意义同Ai)的
最长公共子序列的长度;
2)显然有c[0][i]=0,c[i][0]=0(i=0,1,...n),依此赋初值;
3)递推式
if(ai==bj)
c[i][j]=c[i-1][j-1]+1;
else
c[i][j]=max(c[i-1][j],c[i][j-1]);
依此递推得到全部c[i][j]的值;
4)根据数组c[i][j]的值能的到A与B的全部最长公共子序列。
该法时间复杂度为O(n^2),占用空间较多,
也可用数组c[2][n+1]层层递推,但这样不能得到全部最长公共子序列。
以下代码用c[2][n+1]层层递推,输出一个最长递增子序列。
#include <iostream>
using namespace std;

void swap(int *index,int i,int j)//交换函数
{
int temp=index[i];
index[i]=index[j];
index[j]=temp;
}

void insertSort(int *array,int begin,int end)//插入排序
{
int i,j;
for(i=begin+1;i<=end;i++)
{
j=i;
while(j>begin&&array[j]<array[j-1])
{
swap(array,j,j-1);
j--;
}
}
}

void quickSort(int *array,int begin,int end)//快速排序
{
if(end-begin<8)
insertSort(array,begin,end);
else
{
int middle=(begin+end)>>1;
double pivot=array[middle];
swap(array,begin,middle);
int i=begin+1,j=end;
while(i<j)
{
while(i<=end&&array[i]<=pivot)
i++;
while(array[j]>pivot)
j--;
if(i<j)
swap(array,i,j);
}
swap(array,begin,i-1);
quickSort(array,begin,i-2);
quickSort(array,i,end);
}
}


void findMaxSubsequence(int *array,int n)//找最长公共子序列的函数
{
int *sortedArray=new int[n];
for(int i=0;i<n;i++)
{
sortedArray[i]=array[i];
}
quickSort(sortedArray,0,n-1);
int *c1=new int[n+1],*c2=new int[n+1],*pre,*next,*temp;
for(int i=0;i<n+1;i++)
c1[i]=0;
c2[0]=0;
pre=c1;
next=c2;
int *stack=new int[n+1],top=0;
stack[top]=0;
for(int i=0;i<n;i++)
{
for(int j=1;j<n+1;j++)
{
if(array[i]==sortedArray[j-1])
next[j]=pre[j-1]+1;
else
next[j]=(next[j-1]>pre[j])?next[j-1]:pre[j];
}
stack[++top]=next[n];
temp=next;
next=pre;
pre=temp;
}
for(int i=1;i<=top;i++)
{
if(stack[i]>stack[i-1])
cout<<array[i-1]<<" ";
}
cout<<endl;
delete [] sortedArray;
delete [] c1;
delete [] c2;
delete [] stack;
}









main()
{
int a[]={9,8,7,6,5,4,3,2,1};
findMaxSubsequence(a,9);
}


gnefuil 2004-06-25
  • 打赏
  • 举报
回复
改一改就可以记录解了
对于A数组,把它的每一个元素改成一个队列,每次有新的值的时候不是覆盖而是入队就可以了
对n用数学归纳法就可以证明了,很简单
加载更多回复(11)

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧