我对算法有一个与语言无关的问题。
这来自我读过的(可能是简单的)编程挑战。问题是,我太愚蠢而无法弄明白,并且好奇地说它让我烦恼。
目标是通过交换列表中数字的位置,将整数列表按升序排序。每次交换两个数字时,都必须将它们的总和添加到运行总计中。挑战在于生成具有最小可能运行总量的排序列表。 例子:
3 2 1 - 4
1 8 9 7 6 - 41
8 4 5 3 2 7 - 34
虽然如果你愿意,你可以自由地给出答案,如果你宁愿在正确的方向上提供“暗示”(如果可能的话),我宁愿这样做。
答案 0 :(得分:6)
只读前两段你只是想要一个提示。有一个有效的解决方案(除非我当然犯了错误)。首先对列表进行排序。现在我们可以将原始列表编写为不相交周期的产品列表。
例如,5,3,4,2,1有两个循环,(5,1)和(3,4,2)。这个循环可以被认为是从3,4开始,在3的位置,2在4的位置,4在3的位置。点。最终目标是1,2,3,4,5或(1)(2)(3)(4)(5),五个不相交的周期。
如果我们从不同的周期切换两个元素,比如1和3,那么我们得到:5,1,4,2,3和循环符号(1,5,3,4,2)。这两个循环连接成一个循环,这与我们想要做的相反。
如果我们从同一个循环切换两个元素,比如3和4,那么我们得到:循环符号(5,1)(2,4)(3)中的5,4,3,2,1。一个循环分成两个较小的循环。这使我们更接近所有长度为1的循环的目标。请注意,在同一循环中任何两个元素的切换都会将循环分成两个循环。
如果我们能够找出切换一个周期的最佳算法,我们可以将其应用于所有周期并获得整个排序的最佳算法。一种算法是采用循环中的最小元素并将其与其所处的位置进行切换。因此,对于(3,4,2),我们将使用4切换2.这使得我们得到一个长度为1的循环(元素刚刚切换到正确的位置)和一个比以前小的一个循环。然后我们可以再次应用该规则。该算法将最小元素周期长度切换-1次,每隔一个元素切换一次。
将长度为n的循环转换为长度为1的循环需要n-1次运算。每个元素必须至少操作一次(考虑每个要排序的元素,必须将其移动到正确的位置)。我提出的算法对每个元素进行一次操作,所有算法都必须这样做,然后每个其他操作都在最小元素上完成。没有算法可以做得更好。
这个算法需要O(n log n)来排序然后O(n)来混乱循环。求解一个周期需要O(周期长度),所有周期的总长度为n,因此周期操作的成本为O(n)。最终运行时间为O(n log n)。
答案 1 :(得分:3)
我假设内存是免费的,您可以在对真实对象执行之前模拟排序。
一种方法(可能不是最快)是维护优先级队列。队列中的每个节点都由交换成本键入到达那里,它包含当前项目排序和实现该排序的步骤序列。例如,最初它将包含一个0成本节点,其中包含原始数据排序而没有步骤。
运行一个循环,使最低成本的队列项出列,并从该点开始排队所有可能的单交换步骤。继续运行循环,直到队列的头部有一个排序列表。
答案 2 :(得分:2)
我做了一些手工解决其中一个例子的尝试:
由于您需要替换1,因此您可能需要进行详尽的搜索才能完成问题 - 其详细信息已由其他用户发布。请注意,在执行此方法时,如果数据集很大,则会遇到问题。
如果问题允许“关闭”答案,您可以简单地制作一个贪婪的算法,将最大的项目放在适当的位置 - 直接这样做,或者首先将最小的元素交换到该槽中。
答案 3 :(得分:1)
比较和遍历显然是免费的,你可以预先计算一个数字必须行进的“距离”(并且有效地是最终的排序顺序)。谜题是交换算法。
最大限度地减少整体掉期显然很重要。 最大限度地减少大数字的交换也很重要。
我很确定通过无状态评估每个排序无法保证最佳交换过程,尽管您可能经常接近(而不是挑战)。
答案 4 :(得分:1)
我认为这个问题没有一个简单的解决方案,我的方法可能不会优先于优先队列方法。
找出最小的数字,N。 除了N之外,应该交换占据彼此所需位置的任何数字对。 组装(通过暴力)可以相互交换到其期望位置的每组数字的集合,使得在其自身之间对集合进行排序的成本小于用N交换集合的每个元素的成本。 这些集合将包括许多周期。在这些周期内交换,使得最小的数字交换两次。 使用N作为占位符,交换包含N的循环的所有剩余数字。
答案 5 :(得分:0)
作为一个暗示,这充满了动态编程;这可能不足以提示帮助,但我宁愿从太少开始!
答案 6 :(得分:0)
您需按交换次数收费,而不是根据比较次数收取费用。你也没有提到因保留其他记录而受到指控。