回顾经典问题算法:LIS, LCS-(DP类别)

LIS,最长递增子序列
说明见:http://blog.csdn.net/sdjzping/article/details/8759870

 1 #include <iostream>
 2 #include <cstdlib>
 3 
 4 using namespace std;
 5 
 6 int LIS(int* arr, int len) {
 7     if (arr == NULL || len < 1) return 0;
 8     int LIS[len] = {0};
 9     int mlen = 0;
10     for (int i=0; i<len; i++) {
11         LIS[i] = 1;
12         for (int j = 0; j < i; j++) {
13             if (arr[j] < arr[i] && LIS[i] < LIS[j] + 1) {
14                 LIS[i] = LIS[j] + 1;
15             }
16         }
17         if (LIS[i] > mlen) {
18             mlen = LIS[i];
19         }
20     }
21     return mlen;
22 }
23 
24 
25 int main() {
26     int arr[] = {1, -1, 2, -3, 4, -5, 6, -7};
27     int len = sizeof(arr) / sizeof(arr[0]);
28     cout<<LIS(arr, len)<<endl;
29     system("pause");
30     return 0;
31 }

 再给出nlogn的解法,其中len2val数组就是记录当前LIS长度时结尾的数字(可能情况下的最小值,如1,3和1,2同样可以构成长度为2的LIS但是取len2val[2]=2),关于这个数组的详细说明,可以参考第一个给出的连接,相对于第一个算法的改进就是该数组是有序的,可以使用二分搜索,即在数组中找到第一个比待处理值V大或相等的index设为I(就是序列长度),那么这个V必然可以插入到以len2val[I-1]结尾的长度为I-1的序列后部,形成新序列的长度为I,因而更新数组len2val[I] = V(更新是因为当前值肯定是大于等于V的,因为一开始就是根据这个条件进行搜索的)。这个查找的过程可以用STL中的lower_bound来做,这里自己按照源码写了一个直接返回索引的版本,STL中返回的是迭代器(数组迭代器就是元素指针,比较时还需减掉数组起始位置,才能得到索引)。

 1 int idx_lower_bound(int a[], int begin, int end, int target) {
 2     int count = end - begin;
 3     int first = begin;
 4     while (count > 0) {
 5         int step = count/2;
 6         int idx = first + step;
 7         if (a[idx] < target) {
 8             first = ++idx;
 9             count = count - step - 1;
10         } else {
11             count = step;
12         }
13     }
14 
15     return first;
16 }
17 
18 int LIS_NLOGN(int arr[], int len) {
19     if (arr == NULL || len < 1) {
20         return 0;
21     }
22     int* len2idx = new int[len+1];
23 
24     len2idx[1] = arr[0];
25     int maxlen = 1;
26     for (int i=1; i<len; i++) {
27         char ch = arr[i];
28         int upper = idx_lower_bound(len2idx, 0, maxlen + 1, ch);
29         len2idx[upper] = ch;
30         if (upper > maxlen) {
31             maxlen = upper;
32         }
33     }
34     return maxlen;
35 }

 

LCS,最长公共子序列

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 int max(int a, int b) {
 8     return a > b ? a : b;
 9 }
10 
11 int LCS(const char* s1, int len1, const char* s2, int len2) {
12     if (s1 == NULL || s2 == NULL || len1 < 1 || len2 < 1) return 0;
13     
14     int dp[len1 + 1][len2 + 1];
15     
16     for (int i=0; i<=len1; i++) {
17         for (int j=0; j<=len2; j++) {
18             dp[i][j] = 0;
19         }
20     }
21     
22     for (int i=1; i<= len1; i++) {
23         for (int j=1; j<=len2; j++) {
24             if (s1[i-1] == s2[j-1]) {
25                 dp[i][j] = dp[i-1][j-1] + 1;
26             } else {
27                 dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
28             }
29         }
30     }
31     for (int i=0; i<=len1; i++) {
32         for (int j=0; j<=len2; j++) {
33             cout<<" "<<dp[i][j];
34         }
35         cout<<endl;
36     }
37     return dp[len1][len2];
38 };
39 
40 int main() {
41     const char* s1 = "helloyyc";
42     const char* s2 = "xellxddc";
43     
44     cout<<LCS(s1, strlen(s1), s2, strlen(s2))<<endl;
45 
46     system("pause");
47     return 0;
48 }

 

posted @ 2015-03-02 17:40  卖程序的小歪  阅读(308)  评论(0编辑  收藏  举报