1. O(n^2)
传统的求解方法 ,思路为dp,状态转移方程为 dp[i]=max( dp[j]+1,1)
即到目前的i为止,对前面出现的a[j](j<i)进行遍历 ,如果出现了a[i]>a[j]的情况 ,就使用状态转移方程。
转移方程代表了两种可能 ,第一种为第i个元素自己成为一个上升的队列 ,或者是由于前面的a[j]<a[i] 所以在
dp[j]的基础之上形成了dp[i] = dp[j]+1 但前提是a[i]>a[j]
# include <stdio.h> int a[500]; int dp[500]; int maxx=1; int n; void lis(){ for(int i=0;i<n;i++){ dp[i]=1; for(int j=0;j<i;j++){ if(a[i]>a[j]){ if(dp[i]<dp[j]+1){ dp[i]=dp[j]+1; } } } if(dp[i]>maxx) maxx=dp[i]; } } void output(){ for(int i=n;i>=0;i--){ if(dp[i]==maxx){ printf("%d--",a[i]); maxx--; } } } int main(){ while(scanf("%d",&n)!=EOF){ maxx = 1; for(int i=0;i<n;i++){ scanf("%d",&a[i]); } lis(); printf("最大的长度为%d\n",maxx); output(); } return 0; }
2. 第二种方法 LIS+LCS 把原序列与从小到大排序后的序列做LCS(最长公共子序列),就能求出LIS
顺便写了一下快排 还有可以再开一个数组来记录求LCS的路径 来解决输出的问题
# include<stdio.h> # include<string.h> int n; int a[500]; int b[500]; int dp[500][500]; int res[500][500]; void swap(int *a,int i,int j){ int tmp = a[i]; a[i] = a[j]; a[j] = tmp; } void qsort(int *a,int left,int right){ if(left>=right) return ; int len = left+1; for(int i=left+1;i<=right;i++){ if(a[i]<a[left]){ swap(a,i,len); len++; } } len--; swap(a,left,len); qsort(a,left,len-1); qsort(a,len+1,right); } void LCS(){ memset(dp,0,sizeof(dp)); memset(res,0,sizeof(res)); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(a[i-1]==b[j-1]) { dp[i][j]=dp[i-1][j-1]+1; res[i][j]=1; } else if(dp[i-1][j]>dp[i][j-1]) { dp[i][j]=dp[i-1][j]; res[i][j]=2; } else { dp[i][j]=dp[i][j-1]; res[i][j]=3; } } } } int main(){ while(scanf("%d",&n)!=EOF){ for(int i=0;i<n;i++){ scanf("%d",&a[i]); b[i]=a[i]; } qsort(a,0,n-1); printf("最长上升子序列为:"); for(int i=0;i<n;i++){ printf("%d ",a[i]); } LCS(); printf("\nLIS的长度为:"); printf("%d\n",dp[n][n]); int i=n,j=n; int len=dp[n][n]; while(len){ if(res[i][j]==1){ printf("%d ",a[i-1]); i--; j--; len--; } else if(res[i][j]==2){ i--; }else if(res[i][j]==3){ j--; } } } return 0; }
3.第三种方法 也是最快的方法 ,O(nlogn) dp+二分
思路: dp[i] 所表示的意思为 在如果LIS的长度为i的话 dp[i]所保存的就是长度为i的LIS的末尾数最小的值
但是这个算法有些问题 就是他求LIS的速度是非常快的 但是如果要输出LIS的话 貌似有点困难
# include <stdio.h> int n; int a[500]; int dp[500]; int main(){ while(scanf("%d",&n)!=EOF){ for(int i=0;i<n;i++){ scanf("%d",&a[i]); } dp[1]=a[0]; int len =1; for(int i=1;i<n;i++){ int left=1; int right=len; while(left<=right){ int mid = (left+right)/2; if(a[i]<dp[mid]) right= mid-1; else left=mid+1; } dp[left] = a[i]; if(left>len) len++; } printf("%d\n",len); } return 0; }
时间: 2024-10-14 12:01:21