题目陈述
- 大意:n朵花排成一圈,最小化相邻两朵花高度差的最大值,输出最大值。
- 约定:将所求值成为丑陋值,即要求最小的丑陋值
算法一:暴力做法
算法思路
- 因为已经知道了有n个数字,我们只需要生成这n个数字的所有排序
- 然后依次计算每个序列的丑陋值,依次更新ans,求出最小的即可
代码实现
class Solution { public: int arrangeFlowers(int n, vector<int>& a) { sort(a.begin(),a.end());//排序 int ans=1e9;//ans初值需要足够大,才能保证第一次就被更新掉 do{ int now=abs(a[n-1]-a[0]);//因为是一个圆排列,首位也要 for(int i=0;i<n-1;i++){ now=max(now,abs(a[i]-a[i+1]));//寻找最大差值 } ans=min(now,ans);//看看是否是更小的丑陋值 } while(next_permutation(a.begin(),a.end()));//继续生成下一个排序 return ans; } };
复杂度分析
- 时间复杂度,构造了所有排序,乘法原理易得为
- 空间复杂度,定义了ans,now,为
算法二:构造法+双端队列
性质引入
- 此处我们想用逆向思维,来倒推他的性质
- 依旧先跟大家说一下结论,再来证明:如果我们将这个环,从最大值处断开(把最大值处变为链的左端),那么这条链必然是先递减再递增的
结论证明
- 我们假设,序列中是否有可能有一处或者几处地方,出现”波浪形“(先增后减再增)?
- 答案是不可能的,下面我给大家解释一下
- 如果出现了这种情况,,避免用太抽象的语言,我给大家举个例子,如下图
如果我们将3,4交换,将”波浪形“调整为”单调型“
那么可以发现,将{3,4}看做一个整体,4在9旁边的差值明显比3在9旁边来的小,3在2旁边的差值也比4在2旁边的差值小
对于最大值来说,我们要构造”单调型“,只能两边都是递减,这样整个序列的类型性质也就被确定了下来
所以我们应该构造
^型
这样的序列,(当然对于最小值构造”V“形也是一样的)
故从从最大值处断开(把最大值处变为链的左端),那么这条链必然是先递减再递增的,得证
算法思路
既然我们知道了性质,那么我们要构造,显然就不难了
(注意:上面我举得例子没按这个来构造,只是为了证明性质)
最大值处来构造
(注意:此处的数组a为排序过的)
既然我们构造的是
^型
那么我们显然应该围绕最大值来做,我们借助双端队列,先放入最大值a[n]
要使最大值两端的数最小,不难看出应该左右各应该放入a[n-1],a[n-2]
接下来我们又要让a[n-1],a[n-2]最小
先考虑a[n-1],因为a[n-2]也被选取了,所以我们只能选择a[n-3]
再考虑a[n-2],不难想到填写的是a[n-4]
此处我们以及看出规律了,从大到小取数字,双端队列前后各放入一个数,这样得到的就是最优的答案
最小值处来构造
- 其实跟上面大同小异
- 构造为
V形
- 从小到大取数字,双端队列前后各放入一个数,这样得到的也是最优的答案
代码实现
- 以下为最大值处来构造
class Solution { public: int arrangeFlowers(int n, vector<int>& a) { sort(a.begin(),a.end());//排序 deque<int> d;//双端队列 for(int i=n-1;i>=0;i--){//从小到大取数字 d.push_back(a[i--]);//放入尾 if(i>=0)d.push_front(a[i]); //放入头 } int ans=abs(d.front()-d.back());//圆排列还需要计算头尾的 差值 int head; for(int i=1;i<n;i++){ head=d.front(); d.pop_front();//双端队列不能直接访问,得先取出来 ans=max(ans,abs(head-d.front()));//计算相邻两个数的差值 } return ans; } };
复杂度分析
- 时间复杂度,排序数组为,构造答案序列、求差值都为,总得为
- 空间复杂度,定义了双端队列,为
算法三:性质法
算法思路
- 算法三本质上面跟算法二没有差别,只是算法二的改进
- 我们可以从上述结论中发现,构造好的序列,除了最大值处,有个跟a[n-1]相邻的,其余的数的左右邻居,都是跟自己差值为2的(a[0],a[1]其实在头尾,最后会接起来)
- 但是a[n]和a[n-1]、a[n-2]谁的差值大,显然是a[n-2],a[0]和a[1]、a[2]谁的差值大,显然是a[2]
- 所以我们只需要通过排序后下标差值为2的数的差值即可求出答案
代码实现
class Solution { public: int arrangeFlowers(int n, vector<int>& a) { if(n==2){//特判两个数的情况 return abs(a[1]-a[0]); } sort(a.begin(),a.end());//排序 int ans=0; for(int i=2;i<n;i+=2)ans=max(ans,a[i]-a[i-2]);//下标为偶数的 for(int i=3;i<n;i+=2)ans=max(ans,a[i]-a[i-2]);//下标为奇数的 return ans; } };
复杂度分析
- 时间复杂度,排序数组为,求差值为,总得为
- 空间复杂度,定义了ans,为