题目描述
给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。
输入格式
第一行包含整数N。
第二行包含N个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤1000,
−109≤数列中的数≤109
普通版
思路分析
动态规划通用步骤:
1.状态表示:
f[i]表示数组nums从1到i,且以nums[i]结尾的上升子序列的最大值集合;
属性:Max
2.状态计算
f[i]初始化为1(即所有数字均不是上升的),f[i]=max{f[i],f[j]+1}
时间复杂度 $O(n^2)$
Java 代码
class Main{
public static void main(String[] args) throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(br.readLine());
int[] nums=Arrays.asList(br.readLine().split(" ")).stream().mapToInt(Integer::parseInt).toArray();
int[] dp=new int[n];
int res=0;
for(int i=0;i<n;i++){
dp[i]=Math.max(dp[i],1);
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
dp[i]=Math.max(dp[j]+1,dp[i]);
}
}
res=Math.max(res,dp[i]);
}
System.out.print(res);
}
}
记录路径
添加一维数组,用来记录上一个转移的下标
时间复杂度 $O(n^2)$
Java 代码
class Main{
public static void main(String[] args) throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(br.readLine());
int[] nums=Arrays.asList(br.readLine().split(" ")).stream().mapToInt(Integer::parseInt).toArray();
int[] dp=new int[n];
int[] g=new int[n];
int maxIdx=0;
for(int i=0;i<n;i++){
dp[i]=Math.max(dp[i],1);
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
if(dp[j]+1>dp[i]){
dp[i]=dp[j]+1;
g[i]=j;
maxIdx=Math.max(maxIdx,i);
}
}
}
}
int i=maxIdx,k=maxIdx;
LinkedList<Integer> res=new LinkedList<>();
while(i-->=0){
if(k>=0){
res.addFirst(nums[k]);
}
if(nums[k]<=nums[g[k]]){
break;
}
k=g[k];
}
for(int t:res){
System.out.print(t+" ");
}
}
}