很显然最终的排序结果必为交叉排布的,且符合[...低 高 低 高...]
的形式;
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])
进阶:如何找出一个满足题设的序列?
- 先求出最大值
- 使用回溯法深搜
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()