GVKun编程网logo

[LeetCode] Longest Increasing Subsequence

18

在这篇文章中,我们将带领您了解[LeetCode]LongestIncreasingSubsequence的全貌,同时,我们还将为您介绍有关(Java)LeetCode300.LongestIncre

在这篇文章中,我们将带领您了解[LeetCode] Longest Increasing Subsequence的全貌,同时,我们还将为您介绍有关(Java) LeetCode 300. Longest Increasing Subsequence —— 最长上升子序列、300. Longest Increasing Subsequence、521. Longest Uncommon Subsequence I - LeetCode、CF568E Longest Increasing Subsequence的知识,以帮助您更好地理解这个主题。

本文目录一览:

[LeetCode] Longest Increasing Subsequence

[LeetCode] Longest Increasing Subsequence

Given an unsorted array of integers,find the length of longest increasing subsequence.

Example:

Input: Output: 4 
Explanation: The longest increasing subsequence is,therefore the length is . [10,9,2,5,3,7,101,18][2,101]4

Note:

  • 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?

O(n^2): dp

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

(Java) LeetCode 300. Longest Increasing Subsequence —— 最长上升子序列

(Java) LeetCode 300. Longest Increasing Subsequence —— 最长上升子序列

Given an unsorted array of integers, find the length of longest increasing subsequence.

Example:

Input: [10,9,2,5,3,7,101,18]
Output: 4 
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.

Note:

  • 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?


 

解法一,O(n2):

直观想一下,选中一个元素,以这个元素为结尾的子序列前面有多少个比他值小的元素,那么以它为结尾的上升子序列就是多少再加一。即当前状态可以由之前的一个或一些状态推导出来,所以可以用动态规划。建立一个一维数组dp,dp[i]表示以nums[i]结尾的最长上升子序列长度。初始都置为1。对于原数组每个元素,二重循环从头遍历原数组,每当找到一个比当前元素小的值,证明至少可以形成一个dp[j]+1的上升子序列,所以dp[i] = max(dp[i], dp[j] + 1),而dp[j]之前已经求得。

 

解法二,O(n log n):

还是想一下“人工”做这个题是什么过程。按照上面的例子来分析:

首先看到10,加入备选集,备选集合为{10};

之后看到了9,没有形成上升序列,那么9不应该加入备选集合。但是因为9小于10,所以如果把10替换成9会增加接下来产生上升序列的机会,且并不影响备选集合元素的个数(因为是替换),所以替换掉,备选集现在有{9};

遇到2道理同上,替换掉9,备选集变成{2};

遇到5,这时候形成了上升序列,此时应该是添加到备选集合,变为{2,5};

遇到3,没有形成上升序列,但还是道理同加入9的情况,如果此时把5替换成3,会增加接下来形成上升序列的机会,且备选集保持上升,并且个数也没变,所以替换掉5,备选集变成{2,3};

遇到7,同遇到5,添加元素,备选集{2,3,7};

遇到101,同上,备选集{2,3,7,101};

遇到18,还是一样,虽然没有形成上升序列,但是如果把101替换掉,那么接下来形成上升序列的机会会增加,并且备选集的上升属性和元素个数都不变,所以替换,备选集变为{2,3,7,18}。

至此所有元素添加完毕,备选集的元素个数就是最长上升子序列长度。但这里注意,备选集里面的元素并不是最后最长子序列的元素。因为在寻找最长子序列的过程中,目标是尽可能的让以后形成上升序列的机会增加,所以进行了替换。

“人工”做出来之后,只要用程序实现思考过程就好。总结起来就是:

如果遇到的元素比备选集合里面的元素都大,那么就添加进去,使得上升序列长度增加;

如果遇到的元素比备选集合里最后一个元素小,那么代表它无法被添加到备选集。但是为了使后面得到上升序列的机会增加,需要在不破坏集合上升属性和元素总数的情况下,替换掉备选集中的元素,那么就是替换掉大于他的元素中最小的那个,这样才能满足条件。

这时候,发现备选集一直是保持有序,寻找替换元素的时候就可以用到二分查找,得到O(n log n)的时间复杂度。其中还要注意的是如果元素已经在备选集合中,是不需要任何操作的,因为它并不能增加上升序列的长度,也不会增加之后遇到上升序列的机会,所以直接跳过。

 


解法一(Java)

class Solution {
    public int lengthOfLIS(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        int[] dp = new int[nums.length];
        int max = 1;
        for (int i = 0; i < nums.length; i++)
            dp[i] = 1;
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j <= i; j++) {
                if (nums[j] < nums[i]) {
                    dp[i] = Math.max(dp[i], 1 + dp[j]);
                    max = max > dp[i] ? max : dp[i];
                }            
            }
        }
        return max;
}

 

解法二(Java)

class Solution {
    public int lengthOfLIS(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        List<Integer> dp = new ArrayList<>();
        dp.add(nums[0]);
        for (int i = 1; i < nums.length; i++) {
            if (dp.contains(nums[i])) continue;
            else if (nums[i] > dp.get(dp.size()-1)) dp.add(nums[i]);
            else if (nums[i] < dp.get(dp.size()-1)) {
                int l = 0, r = dp.size()-1;
                while (l < r) {
                    int mid = l + (r - l) / 2;
                    if (dp.get(mid) < nums[i]) l = mid + 1;
                    else r = mid;
                }
                dp.set(r, nums[i]);
            }
        }
        return dp.size();
    }
}

 

300. Longest Increasing Subsequence

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?


public class Solution {
    public int lengthOfLIS(int[] nums) {
        int []f = new int[nums.length];
        int max = 0;
        for (int i = 0; i < nums.length; i++) {
            f[i] = 1; //至少有自己一个递增子序列
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i] && f[i] <= f[j] + 1) {  //保证只比最大的大1个,前面乱序的不会乱加
                    f[i] = f[j] + 1;
                }
            }
            if (f[i] > max) {
                max = f[i];
            }
        }
        return max;
    }
}

Nums 1,3,5,2,8,4,6
Lis1,2,3,2,4,3

当做到第6位时,当j指针走到nums2的时候lis[i]并不用更新,这是因为此时的lis[i]已经是4了,并没有小于等于lis[j]

521. Longest Uncommon Subsequence I - LeetCode

521. Longest Uncommon Subsequence I - LeetCode

Question

521. Longest Uncommon Subsequence I

Solution

题目大意:给两个字符串,找出非共同子串的最大长度

思路:字符串相等就返回-1,不等就返回长度大的那个长度

Java实现:

public int findLUSlength(String a, String b) {
    int aLength = a.length();
    int bLength = b.length();
    if (aLength != bLength) return Math.max(aLength, bLength);
    if (a.equals(b)) return -1;
    return aLength;
}

2

public int findLUSlength(String a, String b) {
    if (a.equals(b)) return -1;
    return Math.max(a.length(), b.length());
}

CF568E Longest Increasing Subsequence

CF568E Longest Increasing Subsequence

先留个坑,输出方案的地方还得再想想

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 100010;
const int INF = 1e9+7;

int n,m,len,cnt;
int a[maxn],b[maxn],c[maxn];
int pre[maxn],from[maxn],tmp[maxn],v[maxn];

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<''0'' || ch>''9''){ if(ch==''-'') f=-1; ch=getchar(); } while(ch>=''0'' && ch<=''9''){ s=s*10+ch-''0''; ch=getchar(); } return s*f; }

int main(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    m=read();
    for(int i=1;i<=m;i++) b[i]=read();
    sort(b+1,b+1+m);
//    for(int i=1;i<=n;i++) c[i]=INF;
    
    len=0;
    for(int i=1;i<=n;i++){
        if(~a[i]){
            int p=lower_bound(c+1,c+1+len,a[i])-c;
            pre[i]=from[p-1];
            from[p]=i;
            c[p]=a[i];
            if(len<p) len=p;
            
        }else{
            int k=1;
            for(int j=1;j<=m;++j){
                while(k<=len&&c[k]<b[j]) ++k;
                tmp[j]=k;
            }
            if(len<k) len=k;
            for(int j=m;j;j--){
                c[tmp[j]]=b[j];
                from[tmp[j]]=from[tmp[j]-1];
            }
        }
    }
    cnt=0;
    for(int i=from[len];i;i=pre[i]){
        tmp[++cnt]=i;
    }
    tmp[0]=n+1;
    tmp[cnt+1]=0;
    
    a[n+1]=INF; b[m+1]=INF;
    for(int i=cnt+1;i;i--){ // 找到b中填到lis位置上的数 
        int last=a[tmp[i]];
        for(int j=tmp[i]+1;j<tmp[i-1];j++){
            if(!~a[j]){
                int k=upper_bound(b+1,b+1+m,last)-b;
                if(k>m||b[k]>=a[tmp[i-1]]) break;
                v[k]=1;
                last=a[j]=b[k];
            }
        }
    }
    
    for(int i=1,j=1;i<=n;i++){
        if(!~a[i]){
            while(j<m&&v[j]) ++j;
            a[i]=b[j];
            v[j]=1;
        }
    }
    for(int i=1;i<=n;i++){
        printf("%d ",a[i]);
    }printf("\n");
    
    return 0;
}

 

今天关于[LeetCode] Longest Increasing Subsequence的分享就到这里,希望大家有所收获,若想了解更多关于(Java) LeetCode 300. Longest Increasing Subsequence —— 最长上升子序列、300. Longest Increasing Subsequence、521. Longest Uncommon Subsequence I - LeetCode、CF568E Longest Increasing Subsequence等相关知识,可以在本站进行查询。

本文标签: