例如,我们有数组X[n] = {X0, X1, X2, ... Xn}
目标是对此数组进行排序,使每对之间的差异按升序排列.
例如 X[] = {10, 2, 7, 4}
答案是:
2 7 10 4
4 10 7 2
Run Code Online (Sandbox Code Playgroud)
我有一些代码,但它是蛮力的:)
#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;
}
Run Code Online (Sandbox Code Playgroud)
任何"漂亮"算法的想法?:)
该问题的解决方案并不总是可行。例如,数组X[] = {0, 0, 0}无法按要求“排序”,因为两个差值始终相等。
如果此问题有解决方案,则应按左图所示对数组值进行“排序”:按升序排列的值的某些子集应形成结果数组的前缀,然后按降序排列的所有剩余值应形成其后缀。并且“排序”数组应该是凸的。

这给出了算法的提示:对数组进行排序,然后将其值分成两个凸子集,然后提取这些子集之一并将其附加到末尾(以相反的顺序)。
一个简单的(部分)实现是:对数组进行排序,找到属于凸包的值的子集,然后检查所有剩余的值,如果它们是凸包,则将它们附加在末尾。仅当其中一个子集完全位于另一个子集之下时,该算法才有效。
如果结果子集相交(如右图所示),则可以使用该算法的改进版本:将已排序的数组分割成段,其中一个子集完全位于另一个子集(AB、BC)下方,然后对于其中的每一个段找到凸包并检查剩余子集的凸性。请注意,右图的 X 轴以特殊方式对应于数组索引:对于子集交集(A、B、C),X 对应于升序数组中的索引;交叉点之间的值的 X 坐标根据它们在结果数组中的位置进行缩放。
换句话说,我们可以从最大到最小处理排序数组的每个值,尝试将该值附加到两个子集之一,以使两个子集都保持凸形。首先,我们尝试将新值放置到添加了先前值的子集中。这可能会使之前添加的多个值不适合该子集 - 然后我们检查它们是否都适合其他子集。如果他们这样做 - 将它们移动到其他子集,如果没有 - 将它们保留在“顶部”子集中,但将当前值移动到其他子集。
每个值最多可以从“顶部”子集中添加或删除一次,也可以最多添加到“底部”子集中一次。对于元素上的每个操作,我们只需要检查其最近的两个前任元素。这意味着步骤 2 和 3 最坏情况的时间复杂度为 O(N)。因此总体时间复杂度由步骤 1 的排序算法决定。