覆盤PHP經典問題解決過程

對於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) 輸出的結果和人爲窮舉相同

通過遞歸把這三種情況擴展

  1. 我們必須也用變量代表要取出的數量,也就是 n 取 m,所以輸入的參數就是 n 和 m

  2. 我們要以 p 取1的結果作爲基礎推出上層結果,所以遞歸深入的邊際條件就是,m-遞歸次數=1

  3. 我們每次向上層返回的結果,取出的個數並不固定,所以也必須用變量表示下標,以此來組合新的結果(這是一個觀察結論)

最終的遞歸函數

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;
    }
}
//測試了幾種常見情況,返回結果均正確

最終的應用層

  1. 等待窮舉的數組

  2. 需要取出的個數

 

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個,結果完全正確

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章