LeetCode week 8 : Longest Increasing Subsequence

来源:互联网 发布:lovelive日服数据库 编辑:程序博客网 时间:2024/06/06 07:03

题目

地址:
https://leetcode.com/problems/longest-increasing-subsequence/description/
类别: Dynamic Programming
难度: Medium
描述:
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.

分析

题目要求从一个未排序的数组中寻找出最长递增子序列并输出其长度,注意子序列与子串不同,子串要求必须是原数组连续的一段,但子序列可以不连续,只要元素位置是递增的即可。对此问题,我们可将其转化为有向无环图的最长路径问题。

解决

初始版(O(n2))

在转化为拓扑图时,每个元素指向其后的大于它的元素组成边集E,则:
状态迁移方程:L(j)(以元素j结尾的最长递增子序列长度) = 1 + max{L(i): (i, j) ∈E}
伪代码:

for j = 1, 2, ... , n:    L(j) = 1 + max{L(i): (i, j) ∈E}return max(L(j));

代码实现

class Solution {public:    int lengthOfLIS(vector<int>& nums) {        int length[nums.size() + 1];        length[0] = 1;        int maxL = 0, maxLj;        for(int i = 1; i < nums.size(); i++) {            maxLj = 0;            for(int j = i - 1; j >= 0; j--) {                if(nums[j] < nums[i])   maxLj = max(length[j], maxLj);            }            length[i] = 1 + maxLj;        }        for(int m = 0; m < nums.size(); m++) {            maxL = max(maxL, length[m]);        }        return maxL;    }};

进阶版(O(nlogn))

在上面的方法中,我们不难发现在max{L(i): (i, j) ∈E}这一操作中是存在不必要的比较的,事实上我们只需要维护一个数组 min_num 即可,其中的每一个元素min_num[i] = number表示在所有长度为i的最长递增子序列中,number是所有这些序列最后一个元素中最小的。

例如在[0,1,10, 9, 8, x]中, L(10) = 3, L(9) = 3,L(8) = 3,然后在我们求L(x)的时候,我们并不需要将x与前面所有L = 1的都比较, 只需L(8) = 3这一信息即可,因为若x>8, 则只需与8比较即可(其它不一定满足比x小且长度与8相同);若x<8,则需要与L<3的元素比较。(可利用二分查找迅速定位)

又如[5,2,8,6, 3,6,9,7]的维护过程:
min_num[1] = 5→2
min_num[2] = 8→6→3
min_num[3] = 6
min_num[4] = 9→7
其实感觉有一点贪心的味道:每加入一个元素后都维护当前长度为i的递增子序列的最后一个元素最小,这样后面才更有可能产生更长序列。

代码实现

class Solution {public:    int lengthOfLIS(vector<int>& nums) {        vector<int> min_num;    //store the min number of the last number of sequence whose length is i        for(int i = 0; i < nums.size(); i++) {            auto it = lower_bound(min_num.begin(), min_num.end(), nums[i]);    //return the position in which the element is no smaller than nums[i];if no such position, return  min_num.end()            if(it == min_num.end()) min_num.push_back(nums[i]);            else *it = nums[i];        }        return min_num.size();    }};
原创粉丝点击