leetcode刷题,总结,记录,备忘300

leetcode300,Longest Increasing Subsequence

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(n2) complexity.

Follow up: Could you improve it to O(n log n) time complexity?

Credits:
Special thanks to @pbrother for adding this problem and creating all test cases.

Subscribe to see which companies asked this question

题目提示使用动态规划的方法去做,虽然我之前也见过一些动态规划的题,但是并没有去好好了解这种算法,于是自己也去读了很多别人的博客,并结合这个动态规划的入门题目,进行了一些学习。动态规划内容我也讲不清楚,自己就是理解为一个大的问题,可以分解成一个一个的小问题,然后将每个小的问题的结果缓存下来,然后合成最终问题的解,其中有些规则和使用条件的什么的,实在太抽象了,不能很好的了解,先搁置,以具体题目为目标,再慢慢的了解。

言归正传,这个题目使用动态规划来解,从第一个数开始,算出在每个下标上的最长递增长度,然后取其中最大的一个即可。此时需要一个数组保存每个下标位置上的结果,假设这个数组为len,长度与目标数组相同,并设其第一个元素为1。接着开始从目标数组的第二个下标开始遍历,嵌套的第二个循环从数组头开始,直到当前的下标,获得当前下标为终点的序列的最大递增长度,存放在len数组中,一直遍历完为止,将最大值返回。可能说起来比较抽象,看下代码,用实际数字试一下会更好理解。

这只是一种方法,嵌套循环,耗时比较多,还有一种二分法,先上第一种的代码。

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if (nums.size() == 0)
        {
            return 0;
        }
        
        
        vector<int> len(nums.size());
        len[0] = 1;
        int maxlen = 1;
        
        for (int i = 1; i < nums.size(); ++i)
        {
            int max = 0;
            for (int j = 0; j < i; ++j)
            {
                if (nums[i] > nums[j] && len[j] > max)
                {
                    max = len[j];
                }
            }
            
            len[i] = max + 1;
            if (len[i] > maxlen)
            {
                maxlen = len[i];
            }
        }
        
        return maxlen;
    }
};


第二种方法为二分法,耗时比较少,这种方法非常巧妙。还是需要一个另外的数组,用来保存元素。首先将目标数组第一个数放入临时的数组,然后从第二个下标开始遍历目标数组,与临时数组中最后一个数进行比较大小,如果大的话,将元素放入临时数组,并且用来计算长度的变量同时增加,如果小于的话,就在该临时数组中使用二分的方法寻找比他小的数,放在那个数前面,如果找不到的话,就直接放在头部,,如果有已这个数开头的又一个递增序列的话,如果长度比之前的长,就会覆盖之前的数,并使计算长度的变量变的更大,最后在遍历完目标数组之后,这个长度变量便是最终的结果,光说还是太抽象了,还是上代码。自己实际操作会更有助于理解。

class Solution {
public:
    
    int Bsearch(vector<int> len, int start, int end, int key)
    {
		if (start == end)
		{
			return key > len[start] ? start : start - 1;
		}

        while (start <= end)
        {
            int mid = (start + end) / 2;
            if (key > len[mid] && key < len[mid + 1])
            {
                return mid;
            }
            else if (key < len[mid])
            {
                end = mid - 1;
            }
            else if (key > len[mid])
            {
                start = mid + 1;
            }
            else if (key == len[mid])
            {
                return mid - 1;
            }
        }
        
        return 0;
    }
    
    int lengthOfLIS(vector<int>& nums) {
        if (nums.size() == 0)
        {
            return 0;
        }
        
        vector<int> len(nums.size() + 1);
        int maxlen = 1;
        int n;
        len[1] =  nums[0];
        
        for (int i = 1; i < nums.size(); ++i)
        {
            if (nums[i] > len[maxlen])
            {
                n = ++maxlen;
            }
            else
            {
                n = Bsearch(len, 1, maxlen, nums[i]) + 1;
            }
            
            len[n] = nums[i];
        }
        
        return maxlen;
    }
};
两种算法时长相差了90ms。。。。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值