动态规划(1) 最长递增子序列 leetcode 300系列

来源:互联网 发布:java界面布局类型 编辑:程序博客网 时间:2024/06/15 22:26

300. 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?

dp[i]=max(dp[j])+1,0j<i

LISlength=max(dp[i]),0i<n

dp[i]保存当前节点结尾的最长子序列的长度。对于每一个当前节点,遍历之前的节点,当前节点大于前面的节点时,取前面的节点加一,遍历一遍之后的最大值就是以

当前节点结尾的最长递增子序列

每次内循环都与当前保存的最大值比较,最终返回最大值 O(n2)

class Solution {public:    int lengthOfLIS(vector<int>& nums) {        int n=nums.size();        if(!n) return 0;        vector<int> dp(n,0);        int res=1;        dp[0]=1;        for(int i=1;i<n;i++)        {            int maxsas=0;            for(int j=0;j<i;j++)            {                if(nums[i]>nums[j])                {                    maxsas=max(maxsas,dp[j]);                }            }            dp[i]=maxsas+1;            res=max(res,dp[i]);        }        return res;    }};

二分查找:

也是建立一个矩阵。这个矩阵不是以当前元素结尾的最大长度。而是满足当前最长子序列长度的最小结尾数。比如res[i]=c,指的是,长为i+1的最长子序列的结尾最小是c。

这种方法做的优化是,假如遍历到了i位置,res到了j位置,意思是,目前从0到i位置的最长子序列是j+1,这个最长子序列的结尾最小是res[j]。而这种res一定是递增的,长度为2的结尾最小值不可能比长度为三的结尾最小值大。加入长度为2的结尾最小值是6,那么在当前已扩展区域中,再去找一个数行程长度为三的子序列,这个书一定大于6.

因此,如果在遍历到i+1位置时的数x,在res中二分查找第一个比他大的数y,y之前的数为z。那么x大于z,这说明,从x位置往前看,能找到z比他小,那么x结尾的子序列是x位置序列加一,而y代表的就是这种长度子序列的最小结尾数,所以把y替换成x。

如果二分查找找不到这样的数,说明当前x比现在已知的所有长度的结尾值都大,x可以和最长的那个子序列构成一个更长的子序列。这个时候扩展res数组。

C++中的lower_bound就是查找第一个大于等于查找值的数。有关C++查找的知识参考:

lower_bound()返回值

STL之二分查找 (Binary search in STL)

代码如下:

class Solution {public:    int lengthOfLIS(vector<int>& nums) {            vector<int> res;//res[i]表示长度为i+1的子序列的结尾是res[i]        for(int i=0;i<nums.size();i++)        {            auto it=std::lower_bound(res.begin(),res.end(),nums[i]);            if(it==res.end())//当前数比现有的结尾长度都大,或者现在才开始                res.push_back(nums[i]);            else                *it=nums[i];        }        return res.size();    }    };

类似题目:

354. Russian Doll Envelopes 类似最长递增子序列

646. Maximum Length of Pair Chain 类似与最长子序列但是有简单做法 贪心方法 这道题题意类似,但是可以用贪心解答

求出所有的递增子序列 491

334. Increasing Triplet Subsequence 题意类似,方法无关,巧方法