题目描述:
小易老师是非常严厉的,它会要求所有学生在进入教室前都排成一列,并且他要求学生按照身高不递减的顺序排列。有一次,n个学生在列队的时候,小易老师正好去卫生间了。学生们终于有机会反击了,于是学生们决定来一次疯狂的队列,他们定义一个队列的疯狂值为每对相邻排列学生身高差的绝对值总和。由于按照身高顺序排列的队列的疯狂值是最小的,他们当然决定按照疯狂值最大的顺序来进行列队。现在给出n个学生的身高,请计算出这些学生列队的最大可能的疯狂值。小易老师回来一定会气得半死。
输入描述:
输入包括两行,第一行一个整数n(1 ≤ n ≤ 50),表示学生的人数
第二行为n个整数h[i](1 ≤ h[i] ≤ 1000),表示每个学生的身高
输出描述:
输出一个整数,表示n个学生列队可以获得的最大的疯狂值。
如样例所示:
当队列排列顺序是: 25-10-40-5-25, 身高差绝对值的总和为15+30+35+20=100。
这是最大的疯狂值了。
示例1
输入
5
5 10 25 40 25输出
100
思路:题目的意思是找到一个排序,使相邻两数之间的差值之和最大,很自然的想到在最大值两边安插最小值,得到的差值最大。
这里考虑贪心策略,为有序数组[1,2,3,4,5]为例,有最大差值的两个数当然是[5,1]。接下来为了得到最大差值,要从剩余数组中取离边缘值最远的数字,对于5来说就是2,对于1来说就是4,也就是[2,5,1,4];最后只剩下3,与左右边缘差值相同,左右均可,这里放左边[3,2,5,1,4]。可以看出,我们取数的顺序是(最大、最小)、(次小、次大)、第三大,……。
代码实现中可以用双指针从数组两边往中间走,比较其与队列边缘值大小确定安插位置。具体如下:
def crazy_queue():
n = int(input())
h = list(map(int, input().split()))
h.sort()
# 双指针从两边往中间走
high = len(h) - 1
low = 0
# 记录此时队列边缘值
left = h[high]
right = h[0]
abs_sum = left - right
while high > low:
# 双指针均往中间走一步
high -= 1
low += 1
# 判断较大值应该放左边还是右边
if h[high] - left > h[high] - right:
# 较大值放左边有更大差值,那么较小值就放右边
abs_sum += abs(h[high] - left) + abs(right - h[low])
# 更新队列左右边缘值
left = h[high]
right = h[low]
else:
abs_sum += abs(h[low] - left) + abs(right - h[high])
left = h[low]
right = h[high]
return abs_sum