5

我有 N 个整数,例如 3、1、4、5、2、8、7。可能有一些重复。我想将此序列划分为连续的子序列,以便我们可以从它们形成非递减序列。如何计算最小切割次数?对于上面提到的例子,答案是 6,因为我们可以把这个序列分成 {3}, {1}, {4, 5}, {2}, {7}, {8} 然后形成 {1, 2 , 3, 4, 5, 7, 8}。最快的方法是什么?

假设某些数字可能相等,有谁知道如何解决它?

4

2 回答 2

2

我会在值减小的点将数组切割成非递减段,然后将这些段用作(单个)合并阶段的输入 - 就像在排序合并中一样 - 在可能的情况下,在关系的情况。当您必须从一个片段切换到另一个片段时,为切割创建额外的位置。

输出是排序的,所以这会产生足够的削减来完成这项工作。剪辑是在序列减少的点处产生的,或者在由于原始序列跳过其他地方存在的数字而必须创建间隙的点处产生 - 所以没有所有这些剪辑的任何序列都不能重新排列成排序顺序。

合并开销的最坏情况是初始序列正在减少。如果您使用堆来跟踪接下来要选择的序列,那么这将变成成本为 n log n 的堆排序。通过从堆中提取所有出现的相同值,然后才决定要做什么来处理关系。

于 2015-11-28T16:23:13.897 回答
1

如果列表不包含重复项,则此方法有效。也许这些可以先得到有效的处理。

我们可以使用 Fenwick 树在O(n * log n)时间和空间上计算置换反转向量。O(n)具有相同编号的向量的连续段可以表示不需要切割的部分。不幸的是,它们也可能返回误报,例如,

Array: {8,1,4,5,7,6,3}
Vector: 0,1,1,1,1,2,5

其中63意味着在序列中切割,[1,4,5,7]。为了解决这个问题,我们采用第二个反演向量表示每个元素后面的较小元素的数量。不需要切割两个向量中平行的连续段:

Array:  {8,1,4,5,7,6,3,0}
Vector:  0,1,1,1,1,2,5,7  // # larger preceding
Vector:  7,1,2,2,3,2,1,0  // # smaller following
            |---|  // not cut

Array:   {3,1,4,5,2,8,7}
Vectors:  0,1,0,0,3,0,1
          2,0,1,1,0,1,0
             |---|  // not cut

Array:   {3,1,2,4}
Vectors:  0,1,1,0
          2,0,0,0
           |---|  // not cut
于 2015-11-28T21:48:55.370 回答