對於5個數字的集合[1,2,3,4,5],從中取出3個,不分先後,共有多少種取法?
在解決多規格商品查詢的問題時,這個算法是可行的解決方案之一
分析
3取2 = 3組
4取2 = 6組
5取2 = 10組
4取3 = 4組
5取3 = 10組
6取3 = 20組
從簡單開始
function one($count){
for ($i=1;$i<=$count;$i++){
$rst[] = [$i];
}
return $rst;
}
//運行one(3)輸出 [[1],[2],[3]]
n取2
function two($count){
$rst = one($count - 1);//用到前面 n 取1的結果
foreach($rst as $v){
for ($i=$v[0]+1;$i<=$count;$i++){
$v[1] = $i;
$result[] = $v;
}
}
return $result;
}
//運行 two(4) 輸出[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
n取3
function three($count){
$rst = two($count - 1);//用到前面 n 取2的結果
foreach($rst as $v){
for ($i=$v[1]+1;$i<=$count;$i++){
$v[2] = $i;
$result[] = $v;
}
}
return $result;
}
//運行 three(5) 輸出的結果和人爲窮舉相同
通過遞歸把這三種情況擴展
-
我們必須也用變量代表要取出的數量,也就是 n 取 m,所以輸入的參數就是 n 和 m
-
我們要以 p 取1的結果作爲基礎推出上層結果,所以遞歸深入的邊際條件就是,m-遞歸次數=1
-
我們每次向上層返回的結果,取出的個數並不固定,所以也必須用變量表示下標,以此來組合新的結果(這是一個觀察結論)
最終的遞歸函數
function getAnswer($amount, $need){
if($need == 1){
for ($i=1;$i<=$amount;$i++){
$rst[] = [$i];
}
return $rst;
}else{
$rst = getAnswer($amount-1, $need-1);
foreach($rst as $v){
for ($i=$v[$need-2]+1;$i<=$amount;$i++){
$v[$need-1] = $i;
$result[] = $v;
}
}
return $result;
}
}
//測試了幾種常見情況,返回結果均正確
最終的應用層
-
等待窮舉的數組
-
需要取出的個數
function getFinallyAnswer($array, $pick){
$amount = count($array);
$sub = getAnswer($amount, $pick);
foreach ($sub as $k => $v){
foreach ($v as $per_sub){
$rst[$k][] = $array[$per_sub - 1];
}
}
return $rst;
}
//getFinallyAnswer([7,8,9,10], 3)
//我們可以嘗試一下從[7,8,9,10]中任取3個,結果完全正確