LeetCode 300. Longest Increasing Subsequence

原題連接在這裏:https://leetcode.com/problems/longest-increasing-subsequence/html

題目:算法

Given an unsorted array of integers, find the length of longest increasing subsequence.post

For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.優化

Your algorithm should run in O(n^2) complexity.url

Follow up: Could you improve it to O(n log n) time complexity?spa

題解:.net

相似Largest Divisible Subset.code

DP問題.htm

e.g. nums = {5, 3, 4, 8, 6, 7.}blog

前1個數的LIS長度d(1)=1(序列: 5)

前2個數的LIS長度d(2)=1(序列: 3; 3前面沒有比3小的)

前3個數的LIS長度d(3)=2(序列: 3, 4; 4前面有個比它小的3, 因此d(3)=d(2)+1)

前4個數的LIS長度d(4)=3(序列: 3, 4, 8; 8前面比它小的有3個數,因此 d(4)=max{d(1),d(2),d(3)}+1=3)

OK,分析到這,我以爲狀態轉移方程已經很明顯了,若是咱們已經求出了d(1)到d(i-1),  那麼d(i)能夠用下面的狀態轉移方程獲得:

d(i) = max{1, d(j)+1}, 其中j<i && nums[j]<nums[i]

想要求d(i), 就把i前面的各個子序列中, 最後一個數小於nums[i]的序列長度加1, 而後取出最大的長度即爲d(i). 固然了,有可能i前面的各個子序列中最後一個數都大於A[i], 那麼d(i)=1, 即它自身成爲一個長度爲1的子序列.

dp[i]表示以nums[i]結尾的LIS.

Time Complexity: O(n^2). Space O(n).

AC Java:

 1 public class Solution {
 2     public int lengthOfLIS(int[] nums) {
 3         if(nums == null || nums.length == 0){
 4             return 0;
 5         }
 6         int max = 1;
 7         int [] dp = new int[nums.length];
 8         for(int i = 0; i<nums.length; i++){
 9             dp[i] = 1;
10             for(int j = 0; j<i; j++){
11                 if(nums[j] < nums[i]){
12                     dp[i] = Math.max(dp[i], dp[j]+1);
13                 }
14             }
15             max = Math.max(max,dp[i]);
16         }
17         return max;
18     }
19 }

Follow-up 是要用O(n*logn)時間.

維護一個list, list.get(i) 是指長度i+1時的subarray 的最後一個數字能夠放的最小值。若list.get(2) = 3, 表示長度爲2的subarray尾端最小值是3.

舉例:假設存在一個序列d[1..9] = 2 1 5 3 6 4 8 9 7. 能夠看出來它的LIS長度爲5, [1, 3, 4, 8, 9].
下面一步一步試着找出它。
咱們定義一個序列B, 而後令 i = 1 to 9 逐個考察這個序列。
此外,咱們用一個變量Len來記錄如今最長算到多少了
首先, 把d[1]有序地放到B裏,令B[1] = 2, 就是說當只有1一個數字2的時候,長度爲1的LIS的最小末尾是2. 這時Len=1

而後, 把d[2]有序地放到B裏,令B[1] = 1, 就是說長度爲1的LIS的最小末尾是1, d[1]=2已經沒用了,很容易理解吧。這時Len=1

接着, d[3] = 5, d[3]>B[1], 因此令B[1+1]=B[2]=d[3]=5, 就是說長度爲2的LIS的最小末尾是5, 很容易理解吧。這時候B[1..2] = 1, 5. Len=2

再來, d[4] = 3, 它正好加在1,5之間,放在1的位置顯然不合適,由於1小於3, 長度爲1的LIS最小末尾應該是1, 這樣很容易推知, 長度爲2的LIS最小末尾是3, 因而能夠把5淘汰掉,這時候B[1..2] = 1, 3. Len = 2

繼續, d[5] = 6, 它在3後面, 由於B[2] = 3, 而6在3後面,因而很容易能夠推知B[3] = 6, 這時B[1..3] = 1, 3, 6. 仍是很容易理解吧? Len = 3 了噢。

第6個, d[6] = 4, 你看它在3和6之間,因而咱們就能夠把6替換掉,獲得B[3] = 4. B[1..3] = 1, 3, 4.  Len繼續等於3

第7個, d[7] = 8, 它很大,比4大. 因而B[4] = 8. Len變成4了

第8個, d[8] = 9, 獲得B[5] = 9. Len繼續增大,到5了。

最後一個, d[9] = 7, 它在B[3] = 4和B[4] = 8之間,因此咱們知道,最新的B[4] =7, B[1..5] = 1, 3, 4, 7, 9. Len = 5.

因而咱們知道了LIS的長度爲5.
Note: 這個1,3,4,7,9不是真正的subarray. 它只是存儲的對應長度LIS的最小末尾。有了這個末尾,咱們就能夠一個一個地插入數據。

雖然最後一個d[9] = 7更新進去對於這組數據沒有什麼意義,可是若是後面再出現兩個數字 8 和 9, 那麼就能夠把8更新到d[5], 9更新到d[6], 得出LIS的長度爲6. 

而後應該發現一件事情了:在B中插入數據是有序的,並且是進行替換而不須要挪動——也就是說,咱們可使用二分查找,將每個數字的插入時間優化到O(logN), 因而算法的時間複雜度就下降到了O(NlogN).

Time Complexity: O(nlogn). Space: O(n).

AC Java:

 1 public class Solution {
 2     public int lengthOfLIS(int[] nums) {
 3         if(nums == null || nums.length == 0){
 4             return 0;
 5         }
 6         int max = 1;
 7         int [] minLast = new int[nums.length];
 8         minLast[0] = nums[0];
 9         for(int i = 1; i<nums.length; i++){
10             int pos = bs(minLast, 0, max-1, nums[i]);
11             minLast[pos] = nums[i];
12             if(pos + 1 > max){
13                 max = pos+1;
14             }
15         }
16         return max;
17     }
18     
19     private int bs(int [] nums, int l, int r, int key){
20         if(nums[r] < key){
21             return r+1;
22         }
23         while(l < r){
24             int mid = l+(r-l)/2;
25             if(nums[mid] < key){
26                 l = mid+1;
27             }else{
28                 r = mid;
29             }
30         }
31         return l;
32     }
33 }

跟上Maximum Length of Pair ChainIncreasing Triplet SubsequenceNumber of Longest Increasing SubsequenceLargest Divisible Subset.

Reference: http://blog.csdn.net/left_la/article/details/11951085 

相關文章
相關標籤/搜索