欢迎光临
我们一直在努力

【数据结构与算法】LIS(公共子序列)

#include<iostream>
#include<vector>
using namespace std;
int main()
{
int n; cin >> n;
vector<int>p1(n), p2(n);
vector<int>pos(n + 5);
for (int i = 0; i < n; i++)
{
cin >> p1[i];
pos[p1[i]]=i;
}
vector<int>a(n + 5);
for (int i = 0; i < n; i++)
{
cin >> p2[i];
a[i] = pos[p2[i]];
}
vector<int>tail;
for (int i = 0; i < a.size(); i++)
{
int x = a[i];
auto it = lower_bound(tail.begin(), tail.end(), x);
if (it == tail.end())
{
tail.push_back(x);
}
else
{
*it = x;
}
}
cout << tail.size() << endl;
}

P1439 两个排列的最长公共子序列:从LCS到LIS的降维打击

这道题如果你按“普通LCS”去写,大概率会直接超时。因为数据范围 n ≤ 1e5,经典 O(n²) 的动态规划是扛不住的。

但这题的精髓就在于一句话:

排列的LCS问题,可以转化为LIS问题

这篇文章就把这个转化过程讲清楚,顺便把你这份代码彻底拆明白。


问题回顾;看起来是LCS

题目给你两个排列:

P1:1~n 的一个排列
P2:1~n 的一个排列

要求:

它们的最长公共子序列长度

第一反应:

  • LCS模板

  • dp[i][j]

但一看数据范围:

n ≤ 100000

直接宣告:

不能用传统LCS


关键突破;排列的特殊性质

注意这句话:

两个序列都是 1~n 的排列

这意味着:

  • 没有重复元素

  • 每个数只出现一次

这就是突破口。


核心思路;把值变成位置

我们先处理 P1:

pos[p1[i]] = i;

意思是:

每个数在 P1 中的位置

例如:

P1: 3 2 1 4 5

pos[3]=0
pos[2]=1
pos[1]=2
pos[4]=3
pos[5]=4


然后处理 P2;做映射

a[i] = pos[p2[i]];

什么意思?

把 P2 中的“值”,转换成它在 P1 中的“位置”

例如:

P2: 1 2 3 4 5

→ a: 2 1 0 3 4


关键转化;问题变了

现在问题变成:

在数组 a 中,求最长上升子序列(LIS)

为什么?

因为:

  • 公共子序列 → 相对顺序一致

  • 转成位置后 → 就是“递增”

一句话总结:

LCS → 转化为 LIS(在排列问题中成立)


LIS怎么做;用二分优化

你用的是经典的 O(n log n) 做法:

vector<int> tail;

含义:

tail[i] 表示长度为 i+1 的上升子序列的最小结尾


核心代码解释

auto it = lower_bound(tail.begin(), tail.end(), x);

这一步是关键:

; 找到第一个 >= x 的位置
; 如果没有 → 直接加到末尾
; 如果有 → 替换


为什么可以替换

这是很多人最困惑的地方。

举个例子:

tail = [1, 3, 5]

来了个 x = 2:

替换后 → [1, 2, 5]

虽然看起来“变小了”,但:

更小的结尾 → 更有潜力变长


整体流程串起来

你的代码本质做了三件事:

; 建立位置映射

pos[x] = 在P1中的位置

; 转换数组

a[i] = pos[P2[i]]

; 求LIS

lower_bound + 贪心


时间复杂度分析

  • 映射:O(n)

  • LIS:O(n log n)

总复杂度:

O(n log n)

完全能通过 1e5 数据。


为什么一定要用 lower_bound

这里必须用:

lower_bound(>=)

不能用 upper_bound(>)

原因是:

我们要保证“严格递增”


常见误区

; 还在用二维dp做LCS
直接超时

; 不理解为什么能转LIS
核心是“排列无重复”

; lower_bound用错
会导致结果错误


总结一句话

这题最关键的不是代码,而是这个转化:

排列的LCS → 转换为位置序列 → 求LIS


最后

如果你能掌握这道题,其实你已经掌握了一个非常重要的套路:

降维打击:把二维问题变成一维问题

这在算法里是非常核心的一种能力,比单纯会写代码重要得多。

赞(0)
未经允许不得转载:171主机测评 » 【数据结构与算法】LIS(公共子序列)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址