最长递增子序列和双序列

  1. 给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)。
  2. 从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)。

1、思路:

  定义L(i):以ai为最后一个元素的最长子序列的长度。当i=1或ai<min{a1,a2,...,a(i-1)}时,L(i)=1; 当1≤j≤i-1且aj<ai时,L(i)=max{L(j)}+1。时间复杂度O(n2)。

LIS
 1 #include <iostream>
 2 using namespace std;
 3 #define len(a) (sizeof(a) / sizeof(a[0])) //数组长度
 4 int lis(int arr[], int len)
 5 {
 6     int longest[len];
 7     for (int i=0; i<len; i++)
 8         longest[i] = 1;
 9 
10     for (int j=1; j<len; j++) {
11         for (int i=0; i<j; i++) {
12             if (arr[j]>arr[i] && longest[j]<longest[i]+1){ //注意longest[j]<longest[i]+1这个条件,不能省略。
13                 longest[j] = longest[i] + 1; //计算以arr[j]结尾的序列的最长递增子序列长度
14             }
15         }
16     }
17 
18     int max = 0;
19     for (int j=0; j<len; j++) {
20         cout << "longest[" << j << "]=" << longest[j] << endl;
21         if (longest[j] > max) max = longest[j];  //从longest[j]中找出最大值
22     }
23     return max;
24 }
25 
26 int main()
27 {
28     int arr[] = {1, 4, 5, 6, 2, 3, 8}; //测试数组
29     int ret = lis(arr, len(arr));
30     cout << "max increment substring len=" << ret << endl;
31     return 0;
32 }

   或者定义:B[i]来标记长度为i的增序列的最小数字是多少,遍历原数组对每一个数字插入到B[i]中的合适位置,并记录当前最长len。时间复杂度O(nlogn)。

BiSearchLIS
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 #define N 9 //数组元素个数
 6 int array[N] = {2, 1, 6, 3, 5, 4, 8, 7, 9}; //原数组
 7 int B[N]; //在动态规划中使用的数组,用于记录中间结果,其含义三言两语说不清,请参见博文的解释
 8 int len; //用于标示B数组中的元素个数
 9 
10 int LIS(int *array, int n); //计算最长递增子序列的长度,计算B数组的元素,array[]循环完一遍后,B的长度len即为所求
11 int BiSearch(int *b, int len, int w); //做了修改的二分搜索算法
12 
13 int main()
14 {
15     printf("LIS: %d\n", LIS(array, N));
16 
17     int i;
18     for(i=0; i<len; ++i)
19     {
20         printf("B[%d]=%d\n", i, B[i]);
21     }
22 
23     return 0;
24 }
25 
26 int LIS(int *array, int n)
27 {
28     len = 1;
29     B[0] = array[0];
30     int i, pos = 0;
31 
32     for(i=1; i<n; ++i)
33     {
34         if(array[i] > B[len-1]) //如果大于B中最大的元素,则直接插入到B数组末尾
35         {
36             B[len] = array[i];
37             ++len;
38         }
39         else
40         {
41             pos = BiSearch(B, len, array[i]); //二分查找需要插入的位置
42             B[pos] = array[i];
43         }
44     }
45 
46     return len;
47 }
48 
49 //修改的二分查找算法,返回数组元素需要插入的位置。
50 int BiSearch(int *b, int len, int w)
51 {
52     int left = 0, right = len - 1;
53     int mid;
54     while (left <= right)
55     {
56         mid = left + (right-left)/2;
57         if (b[mid] > w)
58             right = mid - 1;
59         else if (b[mid] < w)
60             left = mid + 1;
61         else    //找到了该元素,则直接返回
62             return mid;
63     }
64     return left;//数组b中不存在该元素,则返回该元素应该插入的位置
65 }

 

 

posted on 2013-03-24 10:37  月moon鸟  阅读(408)  评论(0编辑  收藏  举报

导航