關於若干資料平均放入若干個盒子的問題

生活無限好發表於2017-08-05

前段時間面試碰到的一個很有趣的問題:

有若干條資料,將這些資料平均放入若干個盒子中,盒子的個數有可能新加,有可能減少,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

相關文章