复盘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个,结果完全正确

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值