很显然最终的排序结果必为交叉排布的,且符合[...低 高 低 高...]的形式;
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() 
京公网安备 11010502036488号