第七周:(LeetCode 300) Longest Increasing Subsequence(c++)

来源:互联网 发布:php小炒花生米 编辑:程序博客网 时间:2024/05/18 04:59

原题:
Given an unsorted array of integers, find the length of longest increasing subsequence.
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.
Follow up: Could you improve it to O(n log n) time complexity?

思路:最长递增子序列的问题应该是动态规划的经典问题。常规的解法是O(n^2) ,优化的解法结合二分查找,可以优化到O(n log n) 。

解法一:
时间复杂度:O(n^2),通过时间19ms。代码如下:

class Solution {public:    int lengthOfLIS(vector<int>& nums) {        int len=nums.size();        if(len==0)            return 0;        int lis[len];        //lis[i]表示到下标i的最长子序列的长度        int max=0,tmp=0,res=0;        for(int i=0;i<len;i++){            max=1;            //第二层循环查找nums[j]中可与nums[i]构成序列的前一个数(即比nums[j]小)            //假设这些数的小标为k1,k2,k3,lis[i]=max{lis[k1],lis[k2],lis[k3]}+1            for(int j=0;j<i;j++){                if(nums[j]<nums[i]){                    tmp=lis[j]+1;                    if(tmp>max)                        max=tmp;                }            }            lis[i]=max;        }        //找到lis[len]中的最大值        for(int i=0;i<len;i++){            if(lis[i]>res)                res=lis[i];        }        return res;    }};

解法二:
时间复杂度:O(n log n) ,通过时间3ms,代码如下:

class Solution {public:    vector<int> minNums;    //minNums[i]表示长度为(i+1)的序列最后一个(最大)的数字的值。    //我们的目标是不断地更新minNums[i],使minNums[i]变小以便于构造更长的序列    void Binary_Search(int num){        int len=minNums.size();        int mid=len/2,begin=0,end=len;        while(1){            if(minNums[mid]==num){                return;            }else if(minNums[mid]<num){                begin=mid;                mid=(mid+end)/2;            }else{                //num比minNums[0]还小,直接更新minNums[0],                //同时也排除了mid=0的情况,避免出现mid-1的下标不合法                //在mid!=0和minNums[mid]>num,判断minNums[mid-1]和num的关系                //如果出现minNums[mid-1]<num<minNums[mid],则更新minNums[mid]                if(mid==0){                     minNums[mid]=num;                     return;                }else if(minNums[mid-1]>num){                    end=mid;                    mid=(begin+mid)/2;                }else if(minNums[mid-1]<num){                    minNums[mid]=num;                    return;                }else{                    return;                }            }        }        return;    }    int lengthOfLIS(vector<int>& nums) {        int len=nums.size();        if(len==0)            return 0;        minNums.push_back(nums[0]);        for(int i=1;i<len;i++){            //判断新加进的数与minNums中最后一个数的关系            //如果nums[i]大于minNums最后一个数,说明可以构造更长的子序列,直接加在末尾            if(nums[i]>minNums[minNums.size()-1])                minNums.push_back(nums[i]);            //如果相等,不进行任何操作            else if(nums[i]==minNums[minNums.size()-1])                continue;            //否则二分查找新加进来的数在vector的哪个位置,看是否需要更新minNums的值            else                Binary_Search(nums[i]);        }        return minNums.size();    }};
1 0