LIS

方法一:O(n2)的dphtml

  狀態定義:dp[i] 表示以數 a[i] 結尾的 LIS 值ios

  狀態轉移方程:dp[i] = max(dp[j] + 1, dp[i]) 1 <= j < i && a[i] > a[j]數組

  代碼:優化

 1 #include<iostream>
 2 using namespace std;
 3 const int maxn = 110;
 4 int a[maxn], dp[maxn];
 5 int n, ans = -1;
 6 int main()
 7 {
 8     cin >> n;
 9     for(int i = 1; i <= n; i++)
10     {
11         cin >> a[i];
12         dp[i] = 1;
13     }
14     for(int i = 1; i <= n; i++)
15         for(int j = 1; j < i; j++)
16             if(a[j] < a[i])
17                 dp[i] = max(dp[j] + 1, dp[i]);
18     for(int i = 1; i <= n; i++)
19         ans = max(ans, dp[i]);
20     cout << ans << endl;
21     return 0;
22 }

 

方法二:O(nlogn)的貪心+二分spa

  引入一個數組,暫且命名爲 low[] ,它的含義是:low[i] 表示長度爲 i 的 LIS 序列的最小的最後一個元素。因此,low 數組裏的元素都是遞增的,對於一個遞增的序列,要使它「成長的潛力」儘量大,那麼它目前的最後一個元素就要儘量小。這個思路是正確的,那麼就是 low 數組的維護問題了,當目前遍歷到的這個數 a[i] 比 low 數組尾部數字大的時候,就把目前這個數加入到 low 數組尾部,不然,在low數組中找到第一個大於等於 a[i] 的元素 low[j] ,用 a[i] 去更新 low[j]。這裏就存在着時間的優化,若是你找第一個大於等於 a[i] 的元素時,從頭至尾遍歷,那麼最終的時間複雜度仍是O(n2),這裏能夠用二分來找,二分的複雜度是O(logn),因此總的時間複雜度就是O(nlogn)。.net

  看看代碼吧:code

 1 #include <iostream>
 2 using namespace std;
 3 const int maxn = 100010;
 4 const int INF = 0x3f3f3f3f;
 5 int low[maxn], a[maxn];
 6 int n, len;
 7 int binary_search(int *a, int r, int x)
 8 {
 9     int l = 1, mid;
10     while(l <= r)
11     {
12         mid = (l + r) >> 1;
13         if(a[mid] <= x)
14             l = mid + 1;
15         else
16             r = mid - 1;
17     }
18     return l;
19 }
20 int main()
21 {
22     cin >> n;
23     for(int i = 1; i <= n; i++)
24     {
25         cin >> a[i];
26         low[i] = INF;
27     }
28     low[1] = a[1];
29     len = 1;
30     for(int i = 2; i <= n; i++)
31     {
32         if(a[i] >= low[len])
33             low[++len] = a[i];
34         else
35             low[binary_search(low, len, a[i])] = a[i];
36     }
37     cout << len << endl;
38     return 0;
39 }

 

方法三:O(nlogn)的樹狀數組優化dphtm

  關於這個方法,其實總體思路和第一種沒區別,只是在找數 a[i] 前面的LIS最大值的時候使用樹狀數組結構來優化效率。好比原序列 a[] ,複製一個同樣的序列 b[] ,對 b[] 進行排序和去重(不去重的話就不是嚴格的上升序列),而後遍歷 a[] 數組(由於子序列是創建在原序列的基礎上的),假設咱們遍歷到了 a[i] ,咱們要獲得原序列中在 a[i] 前面的數其中LIS值最大的那個且那個數要比當前 a[i] 小,這二者缺一不可,那麼好,b[] 數組恰好是排序後的數,找到數 a[i] 在 b[] 中的位置下標 p ,那麼也就是要在 b[] 數組中下標從1到p-1(假設咱們的數下標都是從1開始的)中找到LIS值最大的,這裏這個操做就能夠用樹狀數組的區間查詢來實現,設爲 query(p-1) ,則 ans = max(ans,query(p-1)+1) 就能獲得最終的LIS。blog

Reference:排序

http://www.javashuo.com/article/p-nxophhjf-nr.html

http://www.javashuo.com/article/p-cbazxmmc-eb.html

相關文章
相關標籤/搜索