例如我们有数组X[n] = {X0, X1, X2, ... Xn}
目标是对此数组进行排序,使每对之间的差异按升序排列。
例如X[] = {10, 2, 7, 4}
答案是:
2 7 10 4
4 10 7 2
我有一些代码,但这是蛮力:)
#include <stdio.h>
int main(int argc, char **argv)
{
int array[] = { 10, 2, 7, 4 };
int a[4];
for(int i = 0; i < 4; i++){
a[0] = array[i];
for(int j = 0; j < 4; j++){
a[1] = array[j];
if(a[0] == a[1])
continue;
for(int k = 0; k < 4; k++){
a[2] = array[k];
if(a[0] == a[2] || a[1] == a[2])
continue;
for(int l = 0; l < 4; l++){
a[3] = array[l];
if(a[0] == a[3] || a[1] == a[3] || a[2] == a[3])
continue;
if(a[0] - a[1] < a[1] - a[2] && a[1] - a[2] < a[2] - a[3])
printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]);
}
}
}
}
return 0;
}
对“漂亮”算法的想法? :)
答案 0 :(得分:2)
免责声明此解决方案将按差异值排列差异增长的项目。感谢@Will Ness
根据the difference between every pair is in ascending order
要求的一种解决方案。
您只需按升序O(n)* log(n)对数组进行排序,然后从中间开始。你安排这样的元素:
[n/2, n/2+1, n/2-1, n/2+2, n/2-2, n/2+3 ...]
如果更多元素位于第(n / 2)个元素的右侧,则首先转到+1
[n/2, n/2-1, n/2+1, n/2-2, n/2+2, n/2-3 ...]
否则先去-1。
在这里,你可以获得成对的上升差异。
注意!!! 不能保证这个算法会找到最小的差异并从它开始,但我不认为这是要求。
实施例
排序数组:{1, 2, 10, 15, 40, 50, 60, 61, 100, 101}
然后,你选择50(10/2 = 5),60(10/2 + 1 = 6),40等等......
你会得到:{40, 50, 15, 60, 10, 61, 2, 100, 1, 101}
让你有所不同:10, 35, 45, 50, 51, 59, 88, 99, 100
答案 1 :(得分:2)
我们来看看。您的示例数组是{10,2,7,4},您显示的答案是:
2 7 10 4
5 3 -6 differences, a[i+1] - a[i]
4 10 7 2
6 -3 -5
我在这里展示了翻转的差异,这样分析更容易。
因此,目标是在降序顺序中存在差异a[i+1] - a[i]
。显然,一些正差异值将首先,然后一些负。这意味着数组的最大元素将出现在中间的某个位置。到它的左边的正差必须在降的绝对值,并且所述底片向右顺序 - 。在升的绝对值顺序
我们以另一个数组为例:{4,8,20,15,16,1,3}。我们从排序开始:
1 3 4 8 15 16 20
2 1 4 7 1 4 differences, a[i+1] - a[i]
现在,20位于中间,而在右侧之后必须将值逐渐分开。由于解决方案中20左边的差异是正的,因此值本身是升序的,即排序的。因此,在我们选择其中一些移动到最大元素的右侧之后剩下的任何东西,保持原样,并且(正)差异必须按降序排列。如果是,则找到解决方案。
这里没有解决方案。可能性是:
... 20 16 8 (no more) left: 1 3 4 15 (diffs: 2 1 11 5)
... 20 16 4 (no more) left: 1 3 8 15 (diffs: 2 5 7 5)
... 20 16 3 (no more) left: 1 4 8 15 (diffs: 3 4 7 5)
... 20 16 1 (no more) left: 3 4 8 15 ....................
... 20 15 8 (no more) left: 1 3 4 16
... 20 15 4 (no more) left: 1 3 8 16
... 20 15 3 (no more) left: 1 4 8 16
... 20 15 1 (no more) left: 3 4 8 16
... 20 8 (no more) left: 1 3 4 15 16
... 20 4 (no more) left: 1 3 8 15 16
... 20 3 (no more) left: 1 4 8 15 16
... 20 1 (no more) left: 3 4 8 15 16
... 20 (no more) left: 1 3 4 8 15 16
如果没有1和3,可能会有几种解决方案。
答案 2 :(得分:1)
并非总能解决此问题。例如,数组X[] = {0, 0, 0}
无法根据需要进行“排序”,因为两个差异始终相等。
如果此问题有解决方案,则数组值应按“左图”所示进行“排序”:按升序排列的某些子集应构成结果数组的前缀,然后按降序排列所有剩余值形成后缀。 “排序”数组应该是凸的。
这给出了算法的提示:对数组进行排序,然后将其值拆分为两个凸子集,然后提取其中一个子集并在末尾附加(以相反的顺序)。
一个简单的(部分)实现是:对数组进行排序,找到属于convex hull的值的子集,然后检查所有剩余的值,如果它们是凸的,则在末尾附加它们。该算法仅在其中一个子集完全位于另一个子集之下时才有效。
如果生成的子集相交(如右图所示),则可以使用此算法的改进版本:将排序后的数组拆分为其中一个子集完全位于其他子集(AB,BC)之下的段,然后这些段中的每一个都找到凸包,并检查剩余子集的凸度。请注意,右图中的X轴以特殊方式对应于数组索引:对于子集交集(A,B,C),X对应于升序排序数组中的索引;交点之间的值的X坐标根据它们在结果数组中的位置进行缩放。
换句话说,我们可以处理排序数组的每个值,从最大到最小,尝试将此值附加到两个子集之一,使两个子集保持凸。首先,我们尝试将新值放置到添加了先前值的子集中。这可能会使之前添加的几个值不适合此子集 - 然后我们检查它们是否都适合其他子集。如果他们这样做 - 将它们移动到其他子集,如果不是 - 将它们保留在“顶部”子集中,但将当前值移动到其他子集。
每个值最多从“顶部”子集添加或删除一次,也可以最多添加到“底部”子集一次。对于元素上的每个操作,我们只需要检查两个最接近的前辈。这意味着步骤2和3的最坏情况时间复杂度是O(N)。因此,总体时间复杂度由步骤1中的排序算法确定。