今天做爱奇艺的在线笔试时看到这道题目,这个问题本身见过的,但是当时因为一点小疏忽,导致没有做出来。非常可惜。
问题描述:给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1< s2< s3< …< sn并且这个子序列的长度最长。找出这个最长序列。(为了简化该类问题,我们将诸如最长下降子序列及最长不上升子序列等问题都看成同一个问题,其实仔细思考就会发现,这其实只是<符号定义上的问题,并不影响问题的实质)
例如有一个序列:1 7 3 5 9 4 8,它的最长上升子序列就是 1 3 4 8 长度为4.
这是一个典型的动态规划问题,动态规划的本质是什么,就是问题阶段的划分和递归公式!
问题阶段的划分
所以我们来重新定义这个问题:
给定一个数列,长度为N,
设Fk为:以数列中第k项结尾的最长递增子序列的长度.
求F1..FN 中的最大值.
很容易发现现在这个问题已经是一个N阶段的问题了。
递推公式
Fk的值应该这样得到,寻找出max{Fi+1} (ai< aj)。
那么我们的思路就应该已经很清晰了。
#include<vector>
2 #include<iostream>
3 #include<stdio.h>
4
5 #define maxsize 1000
6 using namespace std;
7 #include<algorithm>
8 vector<int> LIS(vector<int> input){
9 int d[maxsize];
10 int p[maxsize];
11 for(int i=0;i<input.size();i++){
12 d[i]=1;
13 p[i]=i;
14 for(int j=0;j<i;j++){
15 if(input[i]>input[j]&&d[i]<=d[j]){
16 d[i]=d[j]+1;
17 p[i]=j;
18 }
19
20 }
21
22 }
23 //find the max_index
24 int max=-INT_MAX;
25 int max_index=0;
26 for(int i=0;i<input.size();i++){
27 if(d[i]>max){
28 max=d[i];
29 max_index=i;
30 }
31
32 }
33 //find the path by p
34 int fa;
35 vector<int> ans;
36 for(fa=max_index;fa!=p[fa];fa=p[fa]){
37 ans.push_back(input[fa]);
38 }
39 ans.push_back(input[fa]);
40 reverse(ans.begin(),ans.end());
41 return ans;
42 }
int main(){
45 vector<int> input;
46 input.push_back(5);
47 input.push_back(56);
48 input.push_back(59);
49 input.push_back(7);
50 input.push_back(71);
51 vector<int> ans=LIS(input);
52 for(auto item:ans)
53 cout<<item<<endl;
54 return 0;
55
56 }