引言
不知道为啥上次放在LCS最后的LIS转LCS的方法在上机题中WA掉了,匆忙之下复制粘贴了别人的板子,感觉很罪恶,还是得总结一下属于自己的板子
O(n 2)
- 分析:我们假设dp[i]表示以arr[i]结尾的最长上升子序列的长度,那么dp[i]就有可能从任何满足 arr[j] < arr[i] 的dp[j]转移来,只需在dp[i]和dp[j] + 1之间取最大值就好了,而这只是对于arr中的任意i所做的操作,最后要得到结果,我们还得在dp[1]到dp[i]中挑出最大值,即为最终答案,详见代码(为了格式化代码,所有变量声明在全局):
输入
void scan(){
for(int i = 1;i <= n;i++){
scanf("%d", &arr[i]);
}
}
初始化
void init(){
ans = 0;
for(int i = 1;i <= n;i++){
dp[i] = 1;//刚开始每个以arr[i]结尾的最长子序列都只有arr[i],故长度为1
}
}
DP
void DP(){
for(int i = 1;i <= n;i++){
for(int j = 1;j < i;j++){
if(arr[j] < arr[i]){
dp[i] = max(dp[i],dp[j] + 1);
}
}
ans = max(ans,dp[i]);
}
}
输出
void print(){
printf("%d\n", ans);
}
O(nlogn)
- 分析:我们这样想一下,在对arr数组扫描的过程中,如果一个单调上升子序列的最后一个元素越小,那么就越有利于在后面接上元素,那么单调上升子序列就会更容易变长,于是用一个low数组,low[i]记录长度为i的单调上升子序列的最后一个元素,可以证明,扫描进行到最后得到的low数组长度,就是最长上升子序列的长度。
- 思路:对于每个arr[i],如果arr[i] > low[ans],则low[ans++] = arr[i],否则在low数组中找到第一个大于等于arr[i]的元素,然后用arr[i]替换之
输入
/*与上一个输入相同*/
初始化
void init(){
ans = 1;//每个序列的最长上升子序列长度最小为
}
OP
void OP(){
low[1] = arr[1];
for(int i = 2;i <= n;i++){
if(arr[i] > low[ans]){
low[++ans] = arr[i];
}
else{
int tmp = lower_bound(low + 1,low + ans,arr[i]) - low;//用lower_bound函数找到大于等于arr[i]的第一个元素
low[tmp] = arr[i];
}
}
}
输出
/*与上一个输出相同*/