数据平均分组算法的一点思考

比如,有一堆整数要分为 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值甚至一个区间,然后通过判断所有结果的标准差来获取到最优分组。但是这样时间复杂度空间复杂度就很高了。