关于若干数据平均放入若干个盒子的问题

前段时间面试碰到的一个很有趣的问题:

有若干条数据,将这些数据平均放入若干个盒子中,盒子的个数有可能新加,有可能减少,20分钟内用代码实现:stuck_out_tongue_closed_eyes:

回来后偶尔想起这个问题,不解决心里总是不舒服的,在网上找了一番之后,不知道是不是打开姿势不对,没有找到自己想要的,于是只好自己动手了,花了一点时间想思路,又花了大概半天的时间将思路实现

仅仅只是实现了功能,下面上代码:

<?php
$a = ['1','2','3','4','5','6','7','8','9','10','11','12','13'];
$b = [
    'a'=>['a1','a2','a3'],
    'b'=>['b1','b2','b3','b4','b5'],
    'c'=>['c1','c2'],
    'd'=>[],
    'e'=>[],
    'f'=>['f1'],
];

// 获取每个盒子里已经放进去的个数
$d = [];
foreach ($b as $k=>$v){
    $d[$k] = count($v);
}
// 获取所有盒子已经放进去的总的个数
$e = array_sum($d);
// 获取需要放的和已经放进去的总和
$f = bcadd(count($a),$e);
// 获取平均每个盒子需要放进去的个数 = 盒子的个数/总个数
$num = floor(bcdiv($f,count($b)));
// 获取多出来的个数
$remainder = fmod($f,count($b));
// 获取每个盒子剩余需要放进去的个数
$g = [];
foreach ($d as $e_k=>$e_v){
    $g[$e_k]['name'] = $e_k;
    $new_num = bcsub($num,$e_v);
    $g[$e_k]['num'] = $new_num;
}
// 如果不能整除,将多余的依次分给各个盒子,直到分完为止
$new_g = array_values($g);
//print_r($new_g);die;
// 求出每个盒子真正应该放的个数
$h = [];
$y = 0;
foreach ($new_g as $g_k=>$g_v){
    // 存放多余数据的时候,先检查当前盒子内是否满足存放条件(已有个数+1是否大于平均每个盒子需要放进去的个数)
    $has_num = $d[$g_v['name']] ?? 0;    // 已经在盒子里面的个数
    // 如果需要放进多余数据,检查当前已有个数+1后是否等于总的平均个数+1(每个盒子分完后多出来的数据才是剩余的数据)
    if(bcadd($has_num,1) > bcadd($num,1)){
        $h[$g_v['name']] = ($g_v['num'] < 0) ? 0 : $g_v['num'];
        continue;
    }
    if(bcadd($y,1) <= $remainder){
        $h[$g_v['name']] = bcadd($g_v['num'],1);
    }else{
        $h[$g_v['name']] = $g_v['num'];
    }
    $y++;
}

$j = get_result_arr($a,$h);

function get_result_arr($arr,$result){
    $i = 0;
    $arrT = [];
    foreach ($result as $r_k=>$r_v){
        $arrT[$r_k] = array_slice($arr, $i ,$r_v);
        $i = bcadd($i,$r_v);
    }
    return $arrT;
}

$m = [];
$merge_arr = [];
foreach ($b as $b_k=>$b_v){
    if(isset($j[$b_k])){
        $merge_arr = $j[$b_k];
    }
    $m[$b_k] = array_merge($b_v,$merge_arr);
}

print_r($m);die;

最后的结果大概是这样

file

有兴趣的大佬欢迎研究一下,看看有没有更简单的方法

file

file

本作品采用《CC 协议》,转载必须注明作者和本文链接
www.haowuliaoa.com
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 5

不错不错 学习学习

7年前 评论
<?php
//**** 初始化若干个题目的条件 ****//
    // 随机若干条数据 10 - 50 条
    $a = [];
    for ($i=0; $i < rand(10, 50); $i++) { 
        $a[] = rand(100, 500);
    }
    // 随机若干个容器 5 - 10个
    $b = [];
    for ($i=0; $i < rand(5, 10); $i++) { 
        $b[] = [];
    }

//**** 功能实现 ****//
    // 分发处理
    $n = count($b); // 如果容器动态添加就放到循环里面
    foreach ($a as $key => $value) {
        // 取余分容器
        $y = $key % $n;
        $b[$y][] = $value;
    }

//**** 打印查看结果 ****//
    // 输出结果
    printf("(%s) %s = [%s];\n",count($a),  '$a', implode(', ', $a));
    foreach ($b as $key => $value) {
        printf("(%s) %s[%s] = [%s];\n", count($value), '$b', $key, implode(', ', $value));
    }

配图纯属秀操作...
file

7年前 评论

@青石 感谢大佬花时间研究:kissing_heart:

7年前 评论

用我上次分享的随机序列生成算法就行了: 假设m条数据,n个盒子,先生成一个随机序列arr,第一个盒子放arr的前floor(m/n)条数据,依此类推,最后一个盒子放最后m%n条数据

7年前 评论

@生活无限好 可能大佬根本没花时间:smile:

7年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!