Height Round

有N(3~50)个人顺时针绕着圆桌坐成一圈,他们都对身高很敏感,组织者需要考虑一个最佳的座次安排,使得任意相邻两人的身高差的最大值达到最小,请打印N个人最后的身高排列,如果存在多个排列,则打印按字典序最优的一个。

 

示例:heights={1,3,4,5,7}, result={1,3,5,7,4}, 此排列下任意相邻两人的身高差最大值是3,且按字典序最优。

 

 

分析:由于人数上限可以达到50,状态总量非常庞大,所以不太适合用状态dp,继续分析,如果队伍的某部分存在M形排列(...峰谷峰...),则通过将矮“峰”并融入高“峰”,有利于改善身高差的分布及降低最大值,所以整体队形应该是单峰状的,按字典序最优则意味着最矮的人排在最前,所以,首先从最矮的人开始,呈现一个“//"状排列。

把后半部分映射到前面,变成形似的两个上坡,可以稍微简化数据结构的表示:按身高升序排列,然后将每个人分别按其所属坡段进行着色(true或false),最大的身高差就从两组人中相邻两者之差中产生。

继续分析如何产生最佳队形,从按身高升序排列的队伍中,假设是{1,2,7,9,15,30,100},先安排前3个人,则他们无论如何排,身高差最大值都是6,所以按字典序最佳就行,得1->2->7,接着继续排9,它应该排在2和7之间,使得最大差最优为7,其他位置都不是最佳,通过继续排其他的人,可以发现后来的高的人,必定是排在前一个队列中最高和次高的两个人之间,如果换到其他位置,都会使其新增的身高差更大。

以上发现启示出一个找最优的最大差的较快方法:将身高按升序排列,然后从第3个人开始,依次计算每个人和他之前间隔1位的人之间的身高差(heights[i]-heights[i-2]),取其中的最大值,就是问题所求的身高差最优解。

上述过程中并没有考虑字典序列最优,仅仅是确定身高差最优解,但是有了身高差最优解MAX后,要获取字典序最优的排列,就变得比较容易了,同样对已经按升序排列的身高队列,进行迭代:从第i个(初始化为0)人开始,找第j个人,使得(heights[j]-heights[i]=MAX),然后标记第j个人属于后坡段,然后将i设为j,继续前面的迭代策略直至结尾。这个方法可以保证我们只把“临界点”处的高的人往后移,从而尽可能多的让矮的人(字典序优先)留在前坡段,应该算一种贪心策略吧。

【弦外音】通过解这道题,倒是也得到一个额外的感悟,就是最优解可以分阶段求。以前做的题多数是最优解和最优路径在迭代完成时就得到,中间为了计算最优路径,不得不额外增加了很多工作,有时还是事倍功半。

 

public int[] getBestRound(int[] heights) { Arrays.sort(heights); if(heights.length<3) return heights; int max = 0; for(int i=2; imax) { i--; move[i] = true; cursor = i; } int[] result = new int[heights.length]; int head=0,tail=heights.length-1; for(int i=0; i

 

你可能感兴趣的:(Height Round)