Given an unsorted array of integers, find the length of longest increasing subsequence.html
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.java
Your algorithm should run in O(n2) complexity.python
Follow up: Could you improve it to O(n log n) time complexity?算法
解法1: 動態規劃DP,相似brute force的解法,維護一個一維dp數組,其中dp[i]表示以nums[i]爲結尾的最長遞增子串的長度。Time: O(n^2)數組
設長度爲N的數組爲{a0,a1, a2, ...an-1),則假定以aj結尾的數組序列的最長遞增子序列長度爲L(j),則L(j)={ max(L(i))+1, i<j且a[i]<a[j] }。也就是說,須要遍歷在j以前的全部位置i(從0到j-1),找出知足條件a[i]<a[j]的L(i),求出max(L(i))+1即爲L(j)的值。最後,咱們遍歷全部的L(j)(從0到N-1),找出最大值即爲最大遞增子序列。時間複雜度爲O(N^2)。app
例如給定的數組爲{5,6,7,1,2,8},則L(0)=1, L(1)=2, L(2)=3, L(3)=1, L(4)=2, L(5)=4。因此該數組最長遞增子序列長度爲4,序列爲{5,6,7,8}。ide
解法2: 二分查找法Binary Search, 維護一個單調遞增子序列,若是當前值小於單調遞增子序列中的某個元素,則替換之,由於單調遞增子序列可否增加,值取決於最後一個元素,替換內部的元素並不影響。Time: O(nlogn)優化
假設存在一個序列d[1..9] = { 2,1 ,5 ,3 ,6,4, 8 ,9, 7},能夠看出來它的LIS長度爲5。
定義一個序列B,而後讓 i = 1 to 9 逐個考察這個序列。用一個變量Len來記錄如今最長LIS長度。
首先,把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。
注意,這個1,3,4,7,9不是LIS,它只是存儲的對應長度LIS的最小末尾。有了這個末尾,咱們就能夠一個一個地插入數據。雖然最後一個d[9] = 7更新進去對於這組數據沒有什麼意義,可是若是後面再出現兩個數字 8 和 9,那麼就能夠把8更新到d[5], 9更新到d[6],得出LIS的長度爲6。
而後發現一件事情:在B中插入數據是有序的,並且是進行替換而不須要挪動——也就是說,可使用二分查找,將每個數字的插入時間優化到O(logN)~~~~~因而算法的時間複雜度就下降到了O(NlogN)~!spa
Java: DPcode
public class Solution { public int lengthOfLIS(int[] nums) { if (nums == null || nums.length == 0) return 0; int max = 1; int[] lens = new int[nums.length]; Arrays.fill(lens, 1); for(int i=1; i<nums.length; i++) { for(int j=0; j<i; j++) { if (nums[j]<nums[i]) lens[i] = Math.max(lens[i], lens[j]+1); } max = Math.max(max, lens[i]); } return max; } }
Java: BS
public class Solution { public int lengthOfLIS(int[] nums) { int[] increasing = new int[nums.length]; int size = 0; for(int i=0; i<nums.length; i++) { int left=0, right=size-1; while (left<=right) { int m=(left+right)/2; if (nums[i] > increasing[m]) left = m + 1; else right = m - 1; } increasing[left] = nums[i]; if (left==size) size ++; } return size; } }
Java: TreeSet
public class Solution { public int lengthOfLIS(int[] nums) { if (nums == null || nums.length == 0) return 0; int max = 1; TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>() { @Override public int compare(Integer i1, Integer i2) { return Integer.compare(nums[i1], nums[i2]); } }); int[] lens = new int[nums.length]; Arrays.fill(lens, 1); for(int i=0; i<nums.length; i++) { if (ts.contains(i)) ts.remove(i); ts.add(i); Set<Integer> heads = ts.headSet(i); for(int head: heads) { lens[i] = Math.max(lens[i], lens[head] + 1); } max = Math.max(max, lens[i]); } return max; } }
Python: BS, T: O(nlogn), S: O(n)
class Solution(object): def lengthOfLIS(self, nums): LIS = [] def insert(target): left, right = 0, len(LIS) - 1 # Find the first index "left" which satisfies LIS[left] >= target while left <= right: mid = left + (right - left) / 2 if LIS[mid] >= target: right = mid - 1 else: left = mid + 1 # If not found, append the target. if left == len(LIS): LIS.append(target); else: LIS[left] = target for num in nums: insert(num) return len(LIS)
Python: DP, T: O(n^2), S: O(n)
class Solution(object): def lengthOfLIS(self, nums): dp = [] # dp[i]: the length of LIS ends with nums[i] for i in xrange(len(nums)): dp.append(1) for j in xrange(i): if nums[j] < nums[i]: dp[i] = max(dp[i], dp[j] + 1) return max(dp) if dp else 0
Python: wo
class Solution(object): def lengthOfLIS(self, nums): """ :type nums: List[int] :rtype: int """ if not nums: return 0 n = len(nums) dp = [1] * n max_len = 1 for i in xrange(n): for j in xrange(i): if nums[i] > nums[j]: dp[i] = max(dp[i], dp[j] + 1) max_len = max(max_len, dp[i]) return max_len
C++:DP
class Solution { public: int lengthOfLIS(vector<int>& nums) { if (nums.size() == 0) return 0; vector<int> dp(nums.size(), 1); int res = 1; for (int i = 1; i < nums.size(); ++i){ for (int j = 0; j < i; ++j){ if (nums[j] < nums[i]){ dp[i] = max(dp[i], 1+dp[j]); } } res = max(res, dp[i]); } return res; } };
C++:BS
class Solution { public: int lengthOfLIS(vector<int>& nums) { if (nums.empty()) return 0; vector<int> ends{nums[0]}; for (auto a : nums) { if (a < ends[0]) ends[0] = a; else if (a > ends.back()) ends.push_back(a); else { int left = 0, right = ends.size(); while (left < right) { int mid = left + (right - left) / 2; if (ends[mid] < a) left = mid + 1; else right = mid; } ends[right] = a; } } return ends.size(); } };
C++:BS
class Solution { public: int lengthOfLIS(vector<int>& nums) { vector<int> dp; for (int i = 0; i < nums.size(); ++i){ int lo = 0, hi = dp.size(); while (lo < hi){ int mi = (lo + hi)/2; if (dp[mi] < nums[i]) lo = mi + 1; else hi = mi; } if (hi == dp.size()) dp.push_back(nums[i]); else dp[hi] = nums[i]; } return dp.size(); } };
相似題目:
[LeetCode] 354. Russian Doll Envelopes 俄羅斯套娃信封
[LeetCode] 673. Number of Longest Increasing Subsequence 最長遞增序列的個數
[LeetCode] 674. Longest Continuous Increasing Subsequence 最長連續遞增序列