JavaScript算法-递归穷举

本文探讨了如何使用JavaScript通过递归实现穷举法,特别是针对子集和全排列问题。首先介绍了穷举法的基本思想,然后通过伪代码和程序实例详细解释了递归在决策问题中的应用,以解决{a, b, c}子集和'ABC'全排列的问题。最后,文章指出了递归穷举在空间复杂度上的挑战,并预告将在下篇分享优化策略。" 101916936,8394759,matplotlib图表详解:饼图、箱线图与棉棒图,"['数据可视化', 'matplotlib', 'Python绘图']

穷举法的基本思想是根据题目的部分条件确定答案的大致范围,并在此范围内对所有可能的情况逐一验证,直到全部情况验证完毕。若某个情况验证符合题目的全部条件,则为本问题的一个解;若全部情况验证后都不符合题目的全部条件,则本题无解。穷举法也称为枚举法。

递归的穷举问题

  • 经典算法求{a, b, c}的子集

数学求解可以很快得出有2^{3}=8个子集, 即2^{n}个解.

集合元素较少我们直接罗列出结果来分析下:

{a, b, c}  {a, b}  {a, c}  {a}  {b, c}  {b}  {c}  {}

观察所有结果后,重点来了: 每个子集我们可以用{T, T, T} {T, T, F}形式来表示

现在可以把枚举问题转化为决策问题,对每个元素我们都去决策它取或者不取

我们用递归的思想来解决这个问题,对所有情况进行决策,我们把问题拆分,什么时候问题足够小就返回结果,问题足够小从图上可以看到是一条线完全走完,即对每种情况中的元素都做一次决策,剩下的我们继续递归去决策

伪代码分析

function find_subset(全集, 决策){

if(每种情况的元素都做了决策) 返回

每种情况还没有决策完成,递归完成决策

}

  • 程序实现
function find_subset(S, decisions){
    //如果所有决策都做完我们直接返回决策结果
    if(S.length == decisions.length){  //决策是一组true false集合
        let decision = [] 
        //根据true/false把对应的元素拿出来
        for(let i=0; i<S.length; i++){
            if(decisions[i]){
                decision.push(S[i])
            }
        }
        return decision.join('')
    }
    //递归进行决策
    let r = []
    //对决策执行yes
    r = r.concat(find_subset(S, decisions.concat(true)))
    //对决策执行no
    r = r.concat(find_subset(S, decisions.concat(false)))
    //返回结果
    return r
}

find_subset(['a','b','c'],decisions=[])
// ["abc", "ab", "ac", "a", "bc", "b", "c", ""]
  • 经典案例求''ABC"的全排列

数学求解可以很快得出有3!=6个解, 即n!个解.

观察下结果["ABC", "ACB", "BAC", "BCA", "CAB", "CBA"]

把枚举问题转化为决策问题

如上图转化为决策问题,不同于子集问题,全排列决策是取值ABC产生三种决策取A取B取C,每次去取没取过但存在于原集合的元素

每条决策线可以使用递归来实现

  • 伪代码分析

function  permutation(str, decisions){

if( 每个decisions决策都已经做完) 直接返回决策结果

每种情况还没有做完决策继续递归完成

}

  • 程序实现
function permutation(str, decisions){
    //每条决策线路完成我们返回决策结果
    if(str.length == decisions.length){
        return decisions
    }

    //没完成决策,继续递归
    let r = []
    //循环不存在decisions中,在str中的元素
    for(let c of str.split('').filter(x => !(decisions.includes(x)))){
        r = r.concat(permutation(str, decisions+c))
    }
    //返回所有结果
    return r
}

let oStr = 'ABC'
permutation(oStr, decisions=[])
//["ABC", "ACB", "BAC", "BCA", "CAB", "CBA"]
  • 思考

枚举问题转化为决策问题,使用递归可以解决

观察decisions数组,每次递归产生决策占用空间较大

求子集问题可以发现空间复杂度竟达到了O(2^{n}) ,如果需要求子集的集合元素有20项,空间消耗太恐怖

可以思考一下有没有更巧妙的做法来对穷举递归进行空间优化!

优化策略下篇将会与大家共同分享

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值