求解包含列表所有元素的最少递增序列数(可从两端构建)
解决思路:混合左向/右向递增序列的最少划分问题
首先明确核心规则:
- 左向递增序列:元素按原列表顺序排列,每个后续元素比前一个大
- 右向递增序列:元素按原列表逆序排列(从右往左取元素),每个后续元素(原列表中更靠左的元素)比前一个大(对应原列表中该序列是递减的)
我们的目标是用最少的左向+右向序列组合覆盖所有元素,且无重复元素。
步骤1:利用已生成的序列集合找最优组合
你已经得到了两个方向的极大覆盖序列:
left_to_right(原列表的极大左向递增序列):[[1,2,3,4,8],[7], [6]]right_to_left(反转列表的极大递增序列,对应原列表的极大右向递增序列):[[6,7,8], [4], [3], [2], [1]]
这些序列是各自方向上能覆盖最多元素的"最大"序列,我们可以通过组合两个方向的序列,避免元素重复覆盖来找到最优解:
具体操作示例
- 优先选择覆盖元素最多的左向序列:
[1,2,3,4,8],它覆盖了{1,2,3,4,8}五个元素 - 剩余未覆盖元素是
{7,6},在right_to_left中找到包含这两个元素的序列[6,7,8],去掉已覆盖的8后,得到右向序列[6,7],正好覆盖剩余元素 - 最终组合为
[[1,2,3,4,8], [6,7]],总序列数为2,即最优解
同理,也可以先选右向序列[6,7,8],再用左向序列[1,2,3,4]覆盖剩余元素,结果一致。
步骤2:通用化解法(适用于任意长度列表)
如果列表更长,我们可以用枚举+贪心的思路来系统求解:
- 枚举左向序列的所有子集:每个子集对应一组左向序列的组合,计算该组合覆盖的元素集合
- 计算剩余元素的最少右向序列数:对于每个左向子集,找出覆盖剩余元素所需的最少右向序列数量(可通过贪心算法:优先选覆盖剩余元素最多的右向序列)
- 记录最小总序列数:遍历所有左向子集,取「左向序列数+右向序列数」的最小值
- 反向验证:同理枚举右向序列子集,再找对应左向序列数,确保没有遗漏更优解
对于短列表(如你的示例长度为7),左向序列只有3个,子集总数仅为8种,计算成本极低。
步骤3:贪心优化(避免枚举所有子集)
如果列表长度较大,枚举所有子集效率太低,可以用以下贪心策略快速逼近最优解:
- 维护两个集合:
covered:已被覆盖的元素集合used_sequences:已选中的序列列表
- 循环执行以下操作,直到
covered包含所有元素:
a. 在左向序列中选未使用过、覆盖未被覆盖元素最多的序列,加入used_sequences,并更新covered
b. 在右向序列中选未使用过、覆盖未被覆盖元素最多的序列,加入used_sequences,并更新covered - 最终
used_sequences的长度就是近似最优解,对于大多数场景已经足够准确
内容的提问来源于stack exchange,提问作者Hertzeh
相关产品推荐
相关产品推荐

