题解 | #牛牛摆放花#
牛牛摆放花
http://www.nowcoder.com/practice/9a11f48530d94188b430db9afe19d20e
思路
题目分析
- 题目给出数组的大小,同时给出了一个数组
- 题目规定数组中元素表示花高
- 题目的数组围成一圈,相邻元素的差值最大值作为这个圈的丑陋值
- 我们要合理排序这个圈中的元素,使这个圈的丑陋值最小
- 返回这个圈的最小丑陋值
- 方法一:暴力(超时)
- 枚举出来所有的排序方案
- 逐个计算出每个圈的丑陋值
- 选出最小的丑陋值
- 时间代价巨大
- 方法二:贪心数学性质
- 我们可以想到这个圈在数组的表现形式应该是先递增,后递减
- 因此排序很重要
- 排序后,将奇数位的元素统一移到前面,偶数位的元素统一移到后面
- 奇偶交替一前一后向中间逼近,使得中间的值是最大的
- 这样做的原因是我们需要丑陋值最小,而丑陋值是和相邻元素之间的差值有关
- 我们只有将递增顺序的全序列一奇一偶地拆分重新排列到数组首尾,才能保证最新的序列相邻元素之间的差值被降到最小
- 否则按照其他方法排列的新序列,丑陋值这个差值只能大于上述安排方案
- 这样贪心地形成了先递增后递减的序列
- 计算出来的圈丑陋值就是最小的
贪心证明(给看不懂上面文字描述的同学具体推理一下):
- 假设存在一组递增的序列a1,a2,a3,...,an,我们将其按照上述贪心策略进行安排之后会形成的序列为a1,a3...,an,...,a4,a2,因此此时丑陋值我们可以计算为max(∣a1−a2∣,∣ai+2−ai∣,∣an−an−1∣(如果n为偶数,n为奇数则无此项))。
- 根据题意,按照这种方法排序的结果我们将其视作一个环状序列,首尾要相接,因此如果这个排列的整体前后错位了也是不影响的。
- 我们使用反证法证明结论
- 假设如果我们不按照此顺序排列(环状呈现的结果不同),则必定会出现有相邻的两个元素存在∣ai−aj∣(i−j>2)比∣ai+2−ai∣要大,因此丑陋值一定比上面的max计算出来的大,因此得证
方法一:暴力(超时)
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 返回按照这些花排成一个圆的序列中最小的“丑陋度”
* @param n int整型 花的数量
* @param array int整型vector 花的高度数组
* @return int整型
*/
int arrangeFlowers(int n, vector<int>& array) {
// write code here
int res = INT_MAX;
while(next_permutation(array.begin(), array.end())) { // 遍历所有的排序方案
int val = abs(array[0] - array[n-1]); // 围成一圈后首位元素要计算一次
for(int i = 0; i < n-1; i++) val = max(val, abs(array[i+1] - array[i])); // 其他元素相邻高度差也要计算
res = min(res, val); // 从每一躺的丑陋值中选出最小的丑陋值
}
return res;
}
};
复杂度分析
- 时间复杂度:O(N!),所有的的排序方案全部要进行
- 空间复杂度:O(1),使用了常量级别的空间大小
方法二:贪心数学性质
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 返回按照这些花排成一个圆的序列中最小的“丑陋度”
* @param n int整型 花的数量
* @param array int整型vector 花的高度数组
* @return int整型
*/
int arrangeFlowers(int n, vector<int>& array) {
// write code here
int cnt[n];
sort(array.begin(), array.end()); // 对原数组排序
int l = 0; // 标记左侧指针
int r = n-1; // 标记右侧指针
for(int i = 0; i < n; i++) { // 对排序后的数据遍历
if(i % 2 == 0) { // 偶数位置的数字重新放到最前面
cnt[l++] = array[i];
}
else { // 奇数位置的数字重新放到最后面
cnt[r--] = array[i];
}
}
int res = 0;
for(int i = 0; i < n - 1; i++) {
res = max(res, abs(cnt[i+1] - cnt[i])); // 重新统计相邻元素高低岔开的最大高度值
}
return res;
}
};
复杂度分析
- 时间复杂度:O(NlogN),主要时间代价消耗在排序上
- 空间复杂度:O(N),使用了一个新的一维数组,量级和原数组大小一致
不会做题写的题解 文章被收录于专栏
哎呀我好笨呀,一不小心又不会了一道题