前段時間面試碰到的一個很有趣的問題:
有若干條資料,將這些資料平均放入若干個盒子中,盒子的個數有可能新加,有可能減少,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;
最後的結果大概是這樣
有興趣的大佬歡迎研究一下,看看有沒有更簡單的方法
()