最长上升子序列(LIS)

最长上升子序列(Longest Increasing Subsequence)

在一个给定序列中{a[i]},按顺序挑选出若干项(不一定连续),组成一个新序列,成为“子序列”.如果子序列中每相邻的两项中后一项比前一项大则称这个子序列为“上升子序列”.在这些上升子序列中长度最长的即为“最长上升子序列”.

O(n^2)做法:

dp[i]为以第i项结尾的最长上升子序列的长度.

有如下状态转移方程:

dp[i] = max{dp[j] + 1 | a[j] < a[i]}

O(nlogn)做法:

维护一个数组w[],w[i]为长度为i的最长上升子序列的最后一项最小是多少.

不难发现w[]是单调的.

证明:

采用反证法

存在x < y

而w[x] > w[y]

设w[x] = a,w[y] = b

因为dp[i] = max{dp[j] + 1 | a[j] < a[i]}

存在一个c < b < a

以c结尾的最长上升子序列长度与以a结尾的最长上升子序列长度相等

所以a不是长度为x的最长上升子序列的最后一个元素的最小值

矛盾

因此w[]是单调的

可以利用w[]通过二分查找确定答案.

code:

const int M = ~0u >> 1;

int w[maxn];

int LIS(int a[],int n)

{

int ans = 1,l,r,mid,ret;

for(int i = 1; i < n; ++i) w[i] = M;

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

l = 0; r = n - 1;

while(l <= r){

mid = (l + r) >> 1;

if(w[mid] < a[i]){

ret = mid;

l = mid + 1;

}

else r = mid - 1;

}

w[ret + 1] = a[i];

ans = max(ans,ret + 1);

}

return ans;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值