如果我们有一个整数数组,那么如果每步的唯一允许操作是:将元素移动到极值,我们如何确定排序它们所需的最小步骤(按升序排列)? 例如,如果我们有
7 8 9 11 1 10
然后在第一步中可以将11移动到右端,在第二步中移动1到左端以获得1 7 8 9 10 11。因此总步数= 2
可以在这里应用冒泡排序吗?但最糟糕的情况是O(n ^ 2)。那么我们怎样才能更有效率地做到?
谢谢。
答案 0 :(得分:2)
这是一个需要O(n log n)时间,O(n)辅助空间以及n个MoveToFront操作的解决方案。
给定输入数组A,使用值/索引对创建第二个数组B,如此......
7 8 9 11 1 10 -> (7 0) (8 1) (9 2) (11 3) (1 4) (10 5)
[this step takes O(n) time and O(n) space]
然后按每对价值的降序排序B ......
(7 0) (8 1) (9 2) (11 3) (1 4) (10 5) -> (11 3) (10 5) (9 2) (8 1) (7 0) (1 4)
[this step takes O(n log n) time]
准备二元搜索树,T。
现在,对于B中的每个元素,请执行以下操作...
Let I be the index of this element.
Let V be the sum of I and the number of elements in T that are greater than I.
Do a MoveToFront operation on the Vth element of A.
Add I to T.
[Both of the operations on T take O(log n) time]
这个算法适用于您的示例数组
(11 3)
I := 3
V := 3 + 0 = 3
MoveToFront(3): 7 8 9 11 1 10 -> 11 7 8 9 1 10
T: () -> (3)
(10 5)
I := 5
V := 5 + 0 = 5
MoveToFront(5): 11 7 8 9 1 10 -> 10 11 7 8 9 1
T: (3) -> (3 5)
(9 2)
I := 2
V := 2 + 2 = 4
MoveToFront(4): 10 11 7 8 9 1 -> 9 10 11 7 8 1
T: (3 5) -> (2 3 5)
(8 1)
I := 1
V := 1 + 3 = 4
MoveToFront(4): 9 10 11 7 8 1 -> 8 9 10 11 7 1
T: (2 3 5) -> (1 2 3 5)
(7 0)
I := 0
V := 0 + 4 = 4
MoveToFront(4): 8 9 10 11 7 1 -> 7 8 9 10 11 1
T: (1 2 3 5) -> (0 1 2 3 5)
(1 4)
I := 4
V := 4 + 1 = 5
MoveToFront(5): 7 8 9 10 11 1 -> 1 7 8 9 10 11
T: (0 1 2 3 5) -> (0 1 2 3 4 5)
我想你可以找到使用少于n个MoveToFront / Back操作对这些数组进行排序的方法,但我认为你不能在O(n log n)时间内找到那些数组。但是,如果这些操作很慢,那么使用需要更多时间进行规划的算法可能是值得的,因此您可以减少这些操作。
答案 1 :(得分:0)
你能澄清一下这个问题吗?当你说列表时,你的意思是一个链表还是一个数组?如果它不是链表,我对有限的操作集感到有点困惑。如果它是链表,您可以修改以平均情况O(nlgn)时间运行的快速排序。
答案 2 :(得分:0)
基本上,您提到的数据结构是链接列表。对于链表,您可以使用quicksort或mergesort(O(nlogn))。
答案 3 :(得分:0)
这对我来说不像是排序问题。您需要找到需要执行的移动次数,但不需要对数组进行排序。我打赌可以比O(n log n)
更快地完成我建议这样的解决方案: 只计算一个[i]> a [i - 1]。这将是你的结果。
论证: 如果你有[i]> a [i-1],意思是a [i]或[i-1]不在他们的位置。所以你可以:
1)将[i-1]移动到数组的开头
2)将[i]移动到数组的末尾。
更新。你需要定义你移动的[i]或[i-1],就像你的阵列示例一样:7 8 9 11 1 10你有两个比较,这显示了没有到位的内容:11> < 1&11> 10.因此,这绝对是动态编程的任务。但是,它仍然比O(n log n)
更快