**给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。**
这个问题,是我在刷leetcode的时候碰到的,我一回想,在编程之美上遇到过,果断翻开手机的PDF,按上面的方法一步步码出了我的代码。
编程之美的思路分三步:
1.提出最基本的算法
那就是线性嵌套遍历,维持一个LIS数组,代表到每一个索引为之的最长子序列的长度,更新它的方式就是在for(int i=0;i
通过思考可以得出,相同长度的子序列可能会有好多个,我们没必要跟相同长度下所有的子序列都进行一番比较,我们只需要跟这些子序列中末值最小的那一个序列进行比较就行了,那么我们就需要再维持一个数组maxV,maxV[i]就用来表示长度为i的子序列中最大值的最小值(这里有点绕啊,想清楚了再往下看)。有了这个数组,我们的第二重遍历就不用从0-i,而改为遍历maxV就行了,maxV的长度最多为maxLen,而maxLen肯定<=nums.size(),因此这样就减少了判断次数,但主题还是O(N^2)的复杂度,还是略显鸡肋。
3.探究maxV的规律
研究maxV之后,我们可以得出结论,maxV必须是递增的!为什么呢?因为如果i < j,而maxV[i]>maxV[j]的话,那就说不通了。你想,假设maxV[3]=3;那么我们来求maxV[2]的值,这个maxV[2]最不济也得小于3,因为我们可以从maxV[3]的这个序列中再分个子序列出来嘛。也就是说,如果i
编程之美在我心中的地位彻底崩塌了,以后,leetcode才是我心中的神。。。编程之美,你大爷。。。枉我以熟读你为自豪那么久。。。
编程之美解法
4ms
int lengthOfLIS(vector<int>& nums) {
if(nums.empty())
return 0;
int n=nums.size();
vector<int>LIS(n,1);
vector<int>maxV{INT_MIN,nums[0]};
int maxLen=1;
for(int i=1;ivector<int>::iterator iter=lower_bound(maxV.begin(),maxV.end(),nums[i]);
int j=distance(maxV.begin(),iter);
LIS[i]=j;
if(LIS[i]>maxLen){
maxLen=LIS[i];
maxV.push_back(nums[i]);
}else if(maxV[j]>nums[i]){
maxV[j]=nums[i];
}
}
return maxLen;
}
leetcode第一解法
0ms
int lengthOfLIS(vector<int>& nums){
vector<int> dp;
for (int i = 0; i < nums.size(); ++i){
auto it = lower_bound(dp.begin(), dp.end(), nums[i]);
if (it == dp.end())
dp.push_back(nums[i]);
else
*it = nums[i];
}
return dp.size();
}