记编程之美的一道经典问题,最长上升子序列问题。

**给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。**

这个问题,是我在刷leetcode的时候碰到的,我一回想,在编程之美上遇到过,果断翻开手机的PDF,按上面的方法一步步码出了我的代码。
编程之美的思路分三步:
1.提出最基本的算法
那就是线性嵌套遍历,维持一个LIS数组,代表到每一个索引为之的最长子序列的长度,更新它的方式就是在for(int i=0;i 2.做出进一步的优化
通过思考可以得出,相同长度的子序列可能会有好多个,我们没必要跟相同长度下所有的子序列都进行一番比较,我们只需要跟这些子序列中末值最小的那一个序列进行比较就行了,那么我们就需要再维持一个数组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,代码量也要十几行,而leetcode上排第一的解法居然0ms即可通过,最关键的,它的代码行数,只有个位数!!!
编程之美在我心中的地位彻底崩塌了,以后,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();
    }

你可能感兴趣的:(c++,leetcode)