很显然最终的排序结果必为交叉排布的,且符合[...低 高 低 高...]的形式;
1.所以先对数列升序排序,很容易想到高的部分是数组的后一半,低的部分是数组的前一半。
2.观察[...低1, 高1, 低2, 高2...]的形式,两两间差的绝对值之和=(高1-低1)+(高1-低2)+(高2-低2)......
3.假设数组无穷多项,则显然高的那一半每个被加了两次,低的那一半每个被减了两次。
4.但由于数组必然不是无穷多项,必会有断开的。要断开的部分必然在升序数组的中间部分:

  • 4.1 若总项数为偶数,则前一半的最后一个被多减去了一次、后一半的第一个被多加上了一次,需要进行修正。
  • 4.2 若总项数为奇数,后一半的第一个依旧被多加上了一次。可以很清楚的知道前一半会被包在后一半中,即[高...低 高 低 高...高],因此此时前一半没有被多减去一次,但高的一半的第二个又被多加上了一次,因此需要补正。

伪码:

nums.sort()
res = (sum(nums[:mid]) - sum(nums[mid:])) * 2 - nums[mid:][0]
if 奇数:
    res += nums[:mid][-1]  # 补正前一半的最后一项
elif 偶数:
    res -= nums[mid:][1]

python题解:

def cal(nums):
    nums.sort()  # 先排个升序
    mid = len(nums) // 2
    less, great = nums[:mid], nums[mid:]
    return 2 * (sum(great) - sum(less)) - great[0] - (great[1] if len(nums) & 1 else -less[-1])

进阶:如何找出一个满足题设的序列?

  1. 先求出最大值
  2. 使用回溯法深搜
def rebuild(nums):
    max_r = cal(nums)  # 得到最大的两两间差的绝对值之和
    n = len(nums)

    def cal_sum(track):
        res = 0
        for i in range(len(track)-1):
            res += abs(nums[track[i]] - nums[track[i+1]])
        return res

    def backtrack(track=[]):
        if len(track) == n:
            if cal_sum(track) == max_r:
                return [nums[i] for i in track]
            else:
                return None

        for i, _ in enumerate(nums):
            if i not in track:
                track.append(i)  # track存的是填入的索引
                res = backtrack(track)
                if res:  # 找到一个即退出
                    return res
                track.pop()
        return None

    return backtrack()