从暴力递归到动态规划

1.什么暴力递归可以继续优化

有重复调用同一个子问题的解,这种递归可以优化;如果每一个子问题都是不同的解,无法优化也不用优化。

2.设计暴力递归的原则

1)每一个可变参数的类型,不要比int类型更加复杂

2)原则1)可以违反,让类型突破到一维线性结构,必须是单一可变参数

3)如果发现原则1)被违反,但不违反原则2),只需做到记忆化搜索即可

4)可变参数的个数能少则少

3.常见的4种尝试模型

1)从左往右的尝试模型

2)范围上的尝试模型

3)多样本位置全对应的尝试模型

4)寻找业务限制的尝试模型

4.暴力递归到动态规划

1)有一个不违反规则的暴力递归,而且的确存在解的重复调用

2)找到哪些参数的变化会影响返回值,对每一个列出变化范围

3)参数间的所有的组合数量,意味着表的大小

4)规定好严格表的大小,分析位置的依赖顺序,从基础填到最终解

5)对于有枚举行为的决策过程,进一步优化

5.什么是记忆化搜索

记忆化搜索的核心思想是在搜索过程中,对于已经计算过的状态,将其结果保存下来,以便在后续的计算中可以直接使用,从而避免重复计算。

记忆化搜索通过创建一个缓存(通常是一个数组或哈希表)来存储子问题的结果。当再次遇到相同的子问题时,算法会直接从缓存中读取结果,而不是重新计算。这样可以显著减少总的计算次数,提高算法的运行速度。

记忆化搜索的实质是动态规划,效率也和动态规划接近,但形式是搜索,更加简单直观,代码也容易编写。同时,记忆化搜索在求解时按自顶向下的顺序进行,每求解一个状态就将其解保存下来,以便后续使用。

6.实例

在一个1-N的一维轴上有一个机器人,机器人现在在cur位置,机器人需要用ret步去到达aim位置,问:共有多少种方法?

暴力递归:

public static int ways(int N,int cur,int aim,int rest){
    return process(N,cur,aim,rest);
}

public static int process(int N,int cur,int aim,int rest){
    if(rest==0){//没有步数可以再移动了
        return cur==aim?1:0;
    }
    if(cur==1){//边界条件:到达最左端
        return process(N,2,aim,rest-1);//只能向右走,否则越界
    }
    if(cur==N){//边界条件:到达最右端
        return process(N,N-1,aim,rest-1);//只能向左走,否则越界
    }
    return process(N,cur-1,aim,rest-1)+process(N,cur+1,aim,rest-1);
    //已经判断过边界条件,因此不再看是否越界
}
    

记忆化搜索:

public static int way2(int N,int cur,int aim,int rest){
    int[][] dp = new int[N+1][rest+1];
    for(int i=0;i<=N;i++){
        for(int j=0;j<=rest;j++){
            dp[i][j]=-1;
        }
    }
    return process(N,cur,aim,rest,dp);
}

public static int process(int N,int cur,int aim,int rest,int[][] dp){
    if(dp[cur][rest]!=-1){//代表已经算过了,不需要再算,直接拿值
        return dp[cur][rest];
    }
    //之前没算过
    int ans=0;
    if(rest==0){
        ans=cur==aim?1:0;
    }else if(cur==1){
        ans=process(N,2,aim,rest-1,dp);
    }else if(cur==2){
        ans=process(N,N-1,aim,rest-1,dp);
    }else{
        ans=process(N,cur-1,aim,rest-1,dp)+process(N,cur+1,aim,rset-1,dp);
    }
    dp[cur][rest]=ans;//填表
    return ans;
}

    
        

动态规划:

1)画表格找依赖关系

2)先填好边界条件,以已知为基础

public static int ways3(int N,int cur,int aim,int rest){
    return process(N,cur,aim,rest);
}
public static int process(int N,int cur,int aim,int rest){
    int[][] dp=new int[N+1][rest+1];
    dp[aim][0]=1;//当rest为0时,只有目标位置才是1
    for(int i=1;i<=rest;rest++){
        dp[1][i]=dp[2][i-1]; 
        for(j=2;j<N;j++){
            dp[j][i]=dp[j-1][i-1]+dp[j+1][i-1];
        }
        dp[N][i]=dp[N-1][i-1];
    }
    return dp[cur][rest];
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值