题解 | #最长递增子序列#

最长递增子序列

http://www.nowcoder.com/practice/30fb9b3cab9742ecae9acda1c75bf927

#include<bits/stdc++.h>
using namespace std;
int max(int a,int b){
    return a>b?a:b;
}
int main(){
    int n;
    cin>>n;
    int *arr=new int[n];
    //申请一个ends数组ends[b]==c的含义是长度为b+1的所有子序列中结尾最小的数时c
    //再申请一个变量right=0,代表ends数组的有效区域,0..right是有效区域
    //再申请一个动态数组dp,dp[i]的含义为以arr[i]结尾的情况下arr[0..i]的最长递增子序列的大小
    int ends[n],right=0,dp[n];
    dp[0]=1;
    for(int i=0;i<n;i++)
        cin>>arr[i];
    ends[0]=arr[0];//所有长度为1的递增子序列中结尾数最小的是arr[0];
    //填写dp数组
    for(int i=1;i<n;i++){
        //二分查找ends数组中大于等于ar[i]的最左边的数
        int l=0,r=right;
        while(l<=r){
            int mid=(l+r)/2;
            if(ends[mid]>=arr[i]){
                r=mid-1;
            }
            else{
                l=mid+1;
            }
        }
        //更新right的范围
        right=max(right,l);
        dp[i]=l+1;
        ends[l]=arr[i];
    }
    //dp数组填写完毕
    //遍历dp数组找到最大且字典序最小的的位置和值
    int Max=dp[0],pos=0;
    int mindata=arr[0];
    for(int i=1;i<n;i++){
        if(dp[i]>Max){
            Max=dp[i];
            pos=i;
            mindata=arr[i];
        }
        else if(dp[i]==Max){
            if(arr[i]<mindata){
                pos=i;
                mindata=arr[i];
            }
        }
    }
    int temp=Max;
    //找到dp数组中最大值和其位置后
    int res[Max];
    res[--Max]=arr[pos];
    //从pos往左找dp[i]==Max&&arr[i]<arr[pos]且最小的
    for(int i=1;i<=temp;i++){
        int min=-1,ans=-1;//值和位置
        for(int j=pos-1;j>=0;j--){
            if(dp[j]==Max&&arr[j]<arr[pos]){
                //找这些符合条件中字典序最小的
                if(min==-1){
                    min=arr[j];
                    ans=j;
                }
                    
                else{
                    if(arr[j]<min){
                        min=arr[j];
                        ans=j;
                    }
                } 
            }
        }
        res[--Max]=min;
        pos=ans;
    }
    for(int i=0;i<temp;i++)
        cout<<res[i]<<" ";
    return 0;
}
全部评论

相关推荐

杨柳哥:这不是普通人,那这个钱的是天才
点赞 评论 收藏
分享
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务