码迷,mamicode.com
首页 > 其他好文 > 详细

最长单调递增子序列 POJ 3903 Stock Exchange .

时间:2015-11-20 23:14:09      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:

题目传送门 : -------->点这里点这里<----------

题目大意:

给出一串正整数,个数为N个。1<=N<=100000。求最长单调递增子序列长度。

样例输入:

6 
5 2 1 4 5 3 
3  
1 1 1 
4 
4 3 2 1

 样例输出:

3 
1 
1

 ===================================================================

最长单调递增子序列问题的DP朴素算法复杂度为 O(n^2);

然而题目中的 N 最大有10^5 一定是超时,因此可以采用nlogn优化。

优化思路一:      DP + 二分查找

         #define MAX 100010

   A[MAX];//记录数字的数组

   DP[MAX];///记录A[i] 的DP 值。

   re[MAX];//记录到 第 i 个数字时,最大的子序列长度为 re[i];

   set[MAX];//记录DP值为 i 的最小的数 为 set[i];

  算法过程与 朴素 的DP算法一致,只是记录了步长一定时最小的数,并使用了二分查找,找出下一个元素的步长。

  更新 re[i];    set[DP[i]] = min(set[DP[i],A[i]);

  =================================================================================

优化思路二:      贪心 + 二分查找

    非常神奇的一个事情,这题可以不使用DP解决。使用贪心算法。

   贪心策略:

  1. 初始化一个数组 d[MAX] 初始化为 0 , 变量 len = 0;
  2. 读入一个数字  num 。
  3. 如果num > d[len] , d[len++] = num; 继续 2 。
  4. 如果num >= d[len] , 使用二分法查看d数组,0 - len 的区域,找出不比num小的最小的数使用num替换他。继续 2 。
  5. 输出 len . 为 最长子序列长度。

   ======================================================

  其实这个算法与思路一是一样的。思路一种可以发现,其实re数组的大部分空间是浪费的,只要记录当前最长的子序列长度即可。而后的set数组记录的是步长为k时最小的数字为set[k];

事实上可以将d数组将这两个数组的功能合并了,首先d数组中的每一个  d[i] 都是步长为 i + 1 时 的 最小的元素。 其次,长度len又是最长子序列的长度。

为什么我们后面的小的元素可以往前插入呢?

    我们最后需要输出的是 子序列的长度 len 而不是子序列的本身,所以往前替换元素不会影响 len 的值。 而如果往前替换元素时发现,新的子序列比原来记录的旧的子序列长,那么也就自动覆盖了原来的序列,当前的len还是最长子序列长。

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX 100010
 5 
 6 using namespace std;
 7 int A[MAX];
 8 int d[MAX];
 9 ////////////////////////////
10 void init()
11 {
12     memset(d,0,MAX * sizeof(int));
13     return ;
14 }
15 
16 int main()
17 {
18     int N;
19     while(~scanf("%d",&N))
20     {
21         init();
22         for(int i = 0 ; i < N ; i++) scanf("%d",&A[i]);
23         int len = 0;
24         for(int i = 0 ; i < N ; i++)
25         {
26             if(d[len] < A[i])
27             {
28                 d[++len] = A[i];
29             }
30             else if (d[len] == A[i]) continue;
31             else
32             {
33                 int l = 0;
34                 int r = len;
35                 int ans = 0;
36                 int key;
37                 while(l <= r)
38                 {
39                     key = (l + r) / 2;
40                     if(d[key] == A[i])
41                     {
42                         ans = key;
43                         break;
44                     }
45                     if(d[key] > A[i])
46                     {
47                         ans = key;
48                         r = key - 1;
49                     }
50                     else
51                     {
52                         l = key + 1;
53                     }
54                 }
55                 d[ans] = A[i];
56             }
57         }
58         cout << len << endl;
59 
60     }
61     return 0;
62 }

 

最长单调递增子序列 POJ 3903 Stock Exchange .

标签:

原文地址:http://www.cnblogs.com/ticsmtc/p/4982503.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!