比如,有一堆整数要分为 N
组,确保每一组尽量相等。这是我看到的一个面试题,觉得这种算法在某些公司的实际项目中应该是有应用场景的。所以就研究一下。
一点思路
- 等分如何衡量:
标准差
。 - 常识性做法,从大到小开始分。
- 分配标准:根据平均值判断。我们知道,基本上没有每组刚好都等于平均值的情况,普遍的情况是均衡分布在平均值上下。所以平均值也需要浮动。
/**
* @intArr 整数数组
* @count 分组数目
* @float 平均值浮动阈值(核心)
*/
function groupIntArr( intArr = [], count = 1, float = 1) {
// 容错略 。。。
// 数组从大到小排序
intArr.sort((a,b) => b - a);
//计算平均值
let avg = intArr.reduce((a,b) => a + b) / count;
let sum = 0; // 临时总和 用于和平均值判断
let resArr = new Array(count) // 初始化
for(var i = 0; i < count -1; i ++) { // 为啥是 count-1 :最后一个分组直接赋予剩余list
resArr[i] = [intArr[0]];
sum = intArr[0];
intArr.shift(); // 记得从原数组删除
// 这里一定要加 “=” ;float 是关键
for (var j = 0; j < intArr.length ; j++) {
if (sum + intArr[j] <= avg + float) {
resArr[i].push(intArr[j]);
sum += intArr[j];
intArr.splice(j,1); //放入结果数组,就从原数组删除
}
}
}
resArr[count -1] = intArr;
// 打点日志
const sumArr = []
resArr.forEach( (item) => {
sumArr.push(item.reduce((a,b) => {return a + b}));
})
console.log('平均数:', avg)
console.log('分组总和:', sumArr.join(','));
return resArr
}
/*** 执行 **/
groupIntArr([11,42,23,4,5,6,4,5,6,11,23,42,56,78,90],3,1)
//[90, 42, 4] [78, 42, 11, 4] [56, 23, 23, 11, 6, 6, 5, 5]
// [90, 42, 4]
// [78, 56]
// [42, 23, 23, 11, 11, 6, 6, 5, 5, 4]
// 平均数: 135.33333333333334
// 分组总和: 136,134,136 (标准差:1.1547)
groupIntArr([11,42,23,4,5,6,4,5,6,11,23,42,56,78,90],3,0)
// 平均数: 135.33333333333334
// 分组总和: 132,134,140 (标准差:4.16333)
groupIntArr([11,42,23,4,5,6,4,5,6,11,23,42,56,78,90],3,2)
// 平均数: 135.33333333333334
// 分组总和: 137,134,135 (标准差:1.52753)
groupIntArr([1100,4200,2300,400,500,600,400,500,600,1100,2300,4200,5600,7800,9000],3)
// 平均数: 13533.333333333334
// 分组总和: 13200,13400,14000 (标准差:416.3332)
groupIntArr([1100,4200,2300,400,500,600,400,500,600,1100,2300,4200,5600,7800,9000],3, 100)
// 平均数: 13533.333333333334
// 分组总和: 13600,13400,13600 (标准差:115.47005)
- 主逻辑:先从大到小排序,从最大的开始分组,然后在不超过数据平均值的情况下逐个分组,最后一个分组直接使用剩余数据。
- 核心:通过
float
控制平均值的浮动可以得到更完美的结果,所以关键就是根据实际数据的情况,选择合适的float
(比如上述代码中,小数据数组float = 1
更适配,大数据数组float = 100
更适配 )。
如果要追求极致,可以通过设置多个
float
值甚至一个区间,然后通过判断所有结果的标准差
来获取到最优分组。但是这样时间复杂度
和空间复杂度
就很高了。