这是一个编码面试问题。我们会给出一个数组random_arr
,我们需要使用 交换函数对其进行排序。
random_arr
中每个元素的交换次数也是有限的。为此,您将获得一个数组parent_arr
,其中包含random_arr
每个元素的互换次数。
约束:
现在我将解释如何声明parent_arr
。如果parent_arr
如下:
parent_arr [] = {a,b,c,d,...,z}然后
a can be swapped at most one time.
b can be swapped at most two times.
如果parent_arr [] = {c,b,a,....,z}则
c can be swapped at most one time.
b can be swapped at most two times.
a can be swapped at most three times
我的解决方案:
对于random_arr []中的每个元素,如果它已经排序,那么它下面有多少个元素。现在从parent_arr []中选择具有最小交换计数的元素,并检查它是否存在于random_arr []中。如果是,如果发生了多次,那么它将有多个位置可以放置。现在选择具有最大交换计数的位置(相当于该位置的元素)并交换它。现在减少该元素的交换计数并对parent_arr []进行排序并重复该过程。
但效率很低,无法证明其正确性。有什么想法吗?
答案 0 :(得分:4)
首先,让我们简化你的算法;然后让我们非正式地证明它的正确性。
观察一旦计算出排序序列中每个数字下面的元素数量,就有足够的信息来确定排序数组中每个相等元素组x
的位置。例如,如果c
重复7次并且前面有21个元素,那么c
将占用范围[21..27]
(所有索引都是从零开始的;范围包括它的目的)。
按照互换次数增加的顺序浏览parent_arr
。对于每个元素x
,找到其目标范围rb
的开头;还要注意其目标范围re
的结束。现在,浏览random_arr
范围的[rb..re]
外元素。如果您看到x
,请将其交换到范围内。交换后,增加rb
。如果您发现random_arr[rb]
等于x
,请继续递增:这些x
已经在正确的位置,您不需要交换它们。
现在让我们证明上述的正确性。观察一旦元素交换到它的位置,它永远不会再移动。当您到达x
中的元素parent_arr
时,已经处理了掉期数较少的所有元素。通过构造算法,这意味着这些元素已经到位。假设x
有k
个允许的掉期数。当你将它交换到它的位置时,你会移出另一个元素。
此替换元素不能为x
,因为在查找目标范围x
中的目标时,算法会跳过[rb..re]
。此外,被替换的元素不能是x
中 parent_arr
下的元素之一,因为x
下面的所有元素都已经存在,因此无法移动。这意味着替换元素的交换计数必须为k+1
或更多。由于到我们完成处理x
时,我们已经耗尽了任何元素上的k
掉期(这很容易通过归纳证明),我们换出的任何元素都为{{1}腾出空间至少有一个剩余的交换,当我们按照x
指示的顺序到达时,我们可以将它交换到位。