960. 删列造序 III
考点
- LIS
- 状态设计
思路
一、问题重述(Problem Restatement)
给定一个字符串数组 \[ \text{strs} = [s_0, s_1, \dots, s_{n-1}] \] 其中每个字符串长度相同,记为 \(m\)。
允许删除若干列(对所有字符串同时删除相同的列),目标是使得:
对于任意一个字符串 \(s_k\),删除后的字符序列是非递减的。
要求删除的列数最少。
二、建模视角的关键转化
1. 从「行」视角转为「列」视角
该问题的关键并不在于单个字符串,而在于列与列之间的相对关系。
将第 \(j\) 列视为一个整体: \[ C_j = (s_0[j], s_1[j], \dots, s_{n-1}[j]) \] 每一列是一个长度为 \(n\) 的字符向量。
2. 列之间的“可连接”关系
若在最终保留的列序列中,列 \(j\) 位于列 \(i\) 之前(\(j < i\)),则必须满足: \[ \forall k \in [0, n-1],\quad s_k[j] \le s_k[i] \] 即: \[ C_j \preceq C_i \quad \text{(逐维不大于)} \] 这是一个偏序关系(partial order),而非全序。
3. 问题的等价表述
在原列顺序不变的前提下,寻找一个最长的列子序列 \[ j_1 < j_2 < \dots < j_t \] 使得 \[ C_{j_1} \preceq C_{j_2} \preceq \dots \preceq C_{j_t} \]
若该最长长度为 \(L\),则最少删除的列数为: \[ m - L \]
三、动态规划建模(LIS-like DP)
1. 状态定义
令: \[ f[i] = \text{以第 } i \text{ 列结尾的最长合法列子序列长度} \] (这里的下标 \(i\) 表示列索引)
2. 状态转移
对于每个 \(i\),枚举所有 \(j < i\): \[ f[i] = \max\Bigl( 1,\; \max_{\substack{j<i \\ C_j \preceq C_i}} (f[j] + 1) \Bigr) \] 其中判定条件为: \[ C_j \preceq C_i \iff \forall k,\; s_k[j] \le s_k[i] \]
3. 初始化与答案
初始: \[ f[i] = 1 \quad (\text{至少保留自己这一列}) \]
最终保留的最多列数: \[ L = \max_i f[i] \]
最小删除列数: \[ m - L \]
4. 时间复杂度
- 枚举列对:\(O(m^2)\)
- 每次比较两列需检查所有字符串:\(O(n)\)
总复杂度: \[ O(m^2 \cdot n) \] 在题目给定约束下是可接受的。
四、为什么不能使用 \(O(n\log n)\) 的 LIS 模板
1. LIS 的 \(O(n\log n)\) 本质依赖什么?
经典 LIS(patience sorting + 二分)依赖以下关键前提:
- 元素之间存在全序关系 任意两个元素都可比较大小;
- 存在“尾部最优”的贪心替换原则: 用更小的尾值替换,不会影响未来扩展。
2. 本题中的列比较是「偏序」
列之间的关系是: \[ C_a \preceq C_b \iff \forall k,\; s_k[a] \le s_k[b] \] 这是一种逐维支配关系(dominance order),常见特点是:
- 可能存在 \(C_a\) 与 \(C_b\) 互不可比
- 无法定义一个一维的“大小”来排序所有列
例如(两行示意): \[ C_1 = (1,3), \quad C_2 = (2,2) \]
- \(1 \le 2\) 但 \(3 \nleq 2\)
- \(2 \nleq 1\)
两列不可比较。
3. 贪心失效的根本原因
- 无法维护单调的
tails[] - 无法用二分定位替换位置
- 不存在“更小尾部一定更优”的交换论证
因此:
本题是 偏序集上的最长链问题(Longest Chain in Poset), 而 \(O(n\log n)\) 的 LIS 只是一维全序上的特殊情况。
结论是: 只能使用 \(O(m^2)\) 级别的 DP,而不能套用 LIS 的 log n 模板。
五、编程实现要点总结
- 列索引作为 DP 的“时间维”
f[i]表示以第 \(i\) 列结尾的最长合法子序列- 判定条件是「所有字符串逐行不下降」
- 结果是
m - max(f[i])
六、AC 代码
1 | class Solution { |