给出数字列表
1 15 2 5 10
我需要获得
1 2 5 10 15
我能做的唯一操作是“在位置Y移动数字X”.
在上面的例子中,我只需要“在第5位移动数字15”.
我希望尽量减少操作次数,但鉴于可用的操作,我无法找到/记住经典算法.
一些背景:
>我正在与一个类似看板的服务的API进行交互.
>我有大约600张卡,我们的错误跟踪器上的一些操作可能意味着在看板中重新排序这600张卡(如果项目的优先级发生变化,多张卡可以同时移动)
>我可以在600次调用API中执行此操作,但我正在尝试尽可能减少该数量.
最佳答案 引理:您可以执行的对列表L(按递增顺序)排序的最小(删除元素,插入元素)对的数量为:
Smin(L) = |L| – |LIC(L)|
其中LIC(L)是最长的子序列.
因此,你必须:
>建立清单的LIC.
>删除不在其中的元素并将其插回适当的位置(使用二分查找).
证明:
通过归纳.
对于大小为1的列表,增长最长的子序列的长度为1!该列表已经排序,因此所需的(del,ins)对的数量是
|L| – |LIC(L)| = 1 – 1 = 0
现在让Ln成为长度为n,1≤n的列表.令Ln 1为通过在Ln的左侧添加元素en 1而获得的列表.
该元素可能会或可能不会影响最长增长子序列.让我们试着看看……
让in,1和in,2是LIC(Ln)(*)的两个第一个元素:
>如果en 1> in,2,然后LIC(Ln 1)= LIC(Ln)
>如果en1≤in,1,则LIC(Ln 1)= en 1 || LIC(LN)
>否则,LIC(Ln 1)= LIC(Ln) – in,1 en 1.我们保持LIC具有最高的第一元素.这是通过从LIC中删除1,并用en 1替换它来完成的.
在第一种情况下,我们删除en 1,因此我们得到Ln的排序.通过诱导假设,这需要n(缺失,插入)对.然后我们必须在适当的位置插入en 1.从而:
S(Ln+1)min = 1 + S(Ln)min
S(Ln+1)min = 1 + n – |LIC(Ln)|
S(Ln+1)min = |Ln+1| – |LIC(Ln+1|
在第二种情况下,我们忽略en 1.我们首先删除不在LIC(Ln)中的元素.必须再次插入这些元素!有
S(Ln)min = |Ln| – |LIC(Ln)|
这样的元素.
现在,我们只需要小心并按正确的顺序插入它们(相对于en 1).最后,它需要:
S(Ln+1)min = |Ln| – |LIC(Ln)|
S(Ln+1)min = |Ln| + 1 – (|LIC(Ln)| + 1)
因为我们有| LIC(Ln 1)| = | LIC(Ln)| 1和| Ln 1 | = | Ln | 1,我们到底有:
S(Ln+1)min = |Ln+1| – |LIC(Ln+1)|
最后一种情况可以通过考虑通过从Ln 1中移除1得到的列表L’n来证明.在那种情况下LIC(L’n)= LIC(Ln 1)并且因此:
|LIC(L’n)| = |LIC(Ln)| (1)
从那里,我们可以对L’n进行排序(这需要| L’n | – | LIC(L’n |由归纳假设.先前的等式(1)导致结果.
(*):如果LIC(Ln)< 2,然后在,2不存在.只需忽略与它的比较.在这种情况下,只有案例2和案例3适用……结果仍然有效