最长递增子序列的两种解法
以LeetCode-300为例:
O(n^2)解法:
dp数组表示以i结尾的最长递增子序列的长度
class Solution { public: int lengthOfLIS(vector<int>& nums) { const int size = nums.size(); if (size == 0) { return 0; } vector<int> dp(size, 1); int res = 1; for (int i = 1; i < size; ++i) { for (int j = 0; j < i; ++j) { if (nums[j] < nums[i]) { dp[i] = max(dp[i], dp[j]+1); } } res = max (res, dp[i]); } return res; } };
O(nlogn)解法:
tails[i]数组定义:长度为i+1最长递增子序列的最小值末尾值
以nums[4,5,6,3]为例
len = 1 : [4], [5], [6], [3] => tails[0] = 3 len = 2 : [4, 5], [5, 6] => tails[1] = 5 len = 3 : [4, 5, 6] => tails[2] = 6
很容易判断tails数组递增,可以应用二分法
(1) if x is larger than all tails, append it, increase the size by 1 (2) if tails[i-1] < x <= tails[i], update tails[i]
class Solution { public: int lengthOfLIS(vector<int>& nums) { vector<int> tails(nums.size(),0); int size=0; for(int t=0;t<nums.size();t++) { int i=0,j=size; while(i!=j) { int mid=(i+j)/2; if(tails[mid]<nums[t])i=mid+1; else j=mid; // 注意这里为了取到右端的值 } tails[i]=nums[t]; if(i==size)size++; } return size; } };