代码改变世界

最长上升子序列

2011-10-08 22:51  ...平..淡...  阅读(147)  评论(0编辑  收藏  举报

纠结了一晚上,总算理解了。。。欣慰~~

方法1
 1 /*
2 动态规划求解思路分析:O(n^2)
3
4 经典的O(n^2)的动态规划算法,设arr[i]表示序列中的第i个数,dp[i]表示从1到i这一段中以i结尾的最长上升子序列的长度,
5 初始时设dp[i] = 0(i = 1, 2, ...,len(arr))。则有动态规划方程:dp[i] = max{1,dp[j]+1} (j=1, 2, ..., i-1, 且arr[j]<arr[i])。
6
7 */
8 #include <iostream>
9 using namespace std;
10 int arr[1000];
11 int dp[1000];
12
13 int LIS(int n)
14 {
15 int i,j,ans; //ans用于保存最终的最长上升子序列的值
16 for(i=0;i<n;++i)
17 dp[i] = 0;
18
19 dp[0] = 1;
20 for(i=1;i<n;++i) //i从第2个元素开始
21 {
22 ans = dp[i];
23 for(j=0;j<i;++j) //遍历从第1个元素到第i-1个元素
24 {
25 //当满足 当前元素的值大于前面元素,并且ans小于前面相应元素的dp值时,为ans重新赋值
26 if( arr[i]>arr[j] && dp[j]>ans )
27 ans = dp[j];
28 }
29 dp[j] = ans+1;
30 }
31 ans = 0;
32 for(i=0;i<n;++i)
33 {
34 if(dp[i]>ans)
35 ans = dp[i];
36 }
37 return ans;
38 }
39
40 int main()
41 {
42 int n;
43 while(cin>>n)
44 {
45 for(int i=0;i<n;++i)
46 cin>>arr[i];
47 cout<<LIS(n)<<endl;
48 }
49 return 0;
50 }

这个花了好长时间......

方法2
 1 /*
2 时间复杂度O(nlogn)
3 别人总结的(觉得很赞),我按自己的理解,做了修改:
4 贪心+二分查找:O(nlogn)
5 开辟一个数组b,类似栈的功能,每次取数组尾元素b[k]和读到的元素arr[i]做比较:
6 1.1 如果arr[i]>b[k],则赋值给b[k+1];
7 1.2 如果arr[i]<b[k],则二分查找栈中的比a大的最小的数,并替换。
8 2.最后序列长度为k的值。
9 这也是很好理解的,对x和y,如果x<y且E[y]<E[x],用E[x]替换E[y],此时的最长序列长度没有改变但序列Q的''潜力''增大。
10 举例:原序列为1,5,8,3,6,7
11 栈为1,5,8,此时读到3,则用3替换5,得到栈中元素为1,3,8, 再读6,用6替换8,得到1,3,6,再读7,得到最终栈为1,3,6,7,最长递增子序列为长度4。
12
13 */
14 #include <iostream>
15 using namespace std;
16
17 int arr[1000];
18 int b[1000];
19
20 int binSearch(int data,int k)
21 {
22 int low = 0,high = k;
23 while(low<=high)
24 {
25 int mid = (low+high)/2;
26 if(data>=arr[mid])
27 low = mid+1;
28 else
29 high = mid-1;
30 }
31 return low;
32 }
33
34 int LIS(int n)
35 {
36 int k = 0;
37 b[0] = arr[0];
38 for(int i=1;i<n;++i)
39 {
40 if(arr[i]>=b[k])
41 {
42 b[++k] = arr[i];
43 }
44 else
45 {
46 int pos = binSearch(arr[i],k);
47 b[pos] = arr[i];
48 }
49 }
50 return k+1;
51 }
52
53 int main()
54 {
55 int n;
56 while(cin>>n)
57 {
58 for(int i=0;i<n;++i)
59 cin>>arr[i];
60 cout<<LIS(n)<<endl;
61 }
62 return 0;
63 }