求数组中最长递增子序列

例如在序列1,-1,2,-3,4,-5,6,-7中,其最长的递增子序列为1,2,4,6。

解法一:假设在目标数组array[]的前i个元素中,最长递增子序列的长度为LIS[i]。那么,LIS[i+1]=max{1,LIS[k]+1},array[i+1]>array[k],forany k<=i。(LIS[i]是指:假设在数组的前i个元素中,以array[i]为最大元素的最长递增子序列的长度)。

思想:穷举的方法,LIS中记录了长度,通过无后效性性质,只需与末尾的array[i]比较即可(很好理解),复杂度为O(N*N+N)=O(N)。

int LIS(int[] array){

    int[] LIS =new int[array.length];

    for(int i =0;i<array.length;i++){

        LIS[i] =1;

        for(int j= 0;j<i;j++){

            if(array[i]>array[j]&&LIS[j]+1>LIS[i]){//穷举比较,获得最长长度

                LIS[i]= LIS[j]+1;}

        }

    }

    returnMax(LIS);

}

解法二:在递增序列中,如果i<j,那么就会有MaxV[i]<MaxV[j],并且不可能出现MaxV[i]>MaxV[j]这情况。

maxV[i]表示长度为i的递增子序列的最大元素的最小值;nMaxLIS表示数组最长递增子序列长度

代码:

int LIS(int[] array){

    int[] maxV =new int[array.length+1];//记录数组中的递增序列信息

    int[] LIS =new int[array.length];

    maxV[1] =array[0];

    maxV[0] =min(array)-1;//数组中最小值-1,边界值。

    for(int i =0;i<LIS.length;i++){

        LIS[i] =1;

    }

    int nMaxLIS =1;

    for(int i = 1;i<array.length;i++){

        int j;

//先考虑当前最大长度子序列,看可否增加,不行再长度递减观察

        for(j =nMaxLIS;j>=0;j--){

            if(array[i]>maxV[j]){

                LIS[i]= j+1;

                break;

            }

        }

//如果当前最长序列大于最长递增序列长度,更新最长信息

        if(LIS[i]>nMaxLIS){

            nMaxLIS= LIS[i];

            maxV[LIS[i]]= array[i];

        }

//如果array[i]比最长递增子序列最大值要小,则替换原先的最大值(前面break处就有array[i]>maxV[j],添maxV[j]<array[i]感觉没啥必要···,有必要,因为上面运行下来maxV[j]不一定小于array[i])

        elseif(maxV[j]<array[i]&&array[i]<maxV[j+1]){

            maxV[j+1]= array[i];

        }

    }

    returnnMaxLIS;

}

时间复杂度为O(N*N)。内部循环穷举查询那边,可以用二分搜索加速,把时间复杂度降为O(N*log2N)。

附加:最长公共上升子序列

f[j]为必选择b[j]为末尾时的最长公共上升子序列

代码如下:

//通过固定a[i],循环b[j]进行比较。很好理解,忘记了,可以结合1,2,0,4,5和1,0,4,5,2的例子跟代码一起理解。

int i,j,k;

for(i=0;i<n;i++){

    k = 0;

    for(j =0;j<m;j++){

        if(a[i]== b[j])

            if(f[j]<f[k]+1)

                    f[j]= f[k]+1;

        //必须要有,很好理解当a[i]值比b[j]大时,需要更新k,因为能够去与f[j]比较了,而a[i]比b[j]小时,是没资格去获取f[j]

        if(a[i]>b[j])

            if(f[k]<f[j])

                k= j;

    }

}

返回max(f(i));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值