记忆化搜索的原理及相关的应用

文章详细阐述了记忆化搜索的原理,通过斐波那契数列的例子展示了如何将递归转化为记忆化搜索,减少冗余计算,将时间复杂度从O(2^n)降低到O(n)。同时,文中提到了快速幂问题的递归与记忆化解法,并给出了动态规划解决最小路径和问题的示例,强调了自底向上和自顶向下的策略差异。
摘要由CSDN通过智能技术生成

首先必须确认的是凡是可以写出动态规划的递归表达式的都可以转化为记忆化搜索

原理

  • 首先从递归表达式入手,对于一个斐波那契数列的问题,使用递归的方式可以进行解决,但是,这样类型的搜索是带有大量冗余的搜索,为了使得搜索的时候能够减小冗余,必须对搜索的过程进行记忆化。(以labuladong的原理图为例)
    在这里插入图片描述 在这里插入图片描述记忆化搜索
int fib(int N) {
    if (N == 1 || N == 2) return 1;
    return fib(N - 1) + fib(N - 2);
}
//递归的方式
//记忆化搜索
int fib(int N) {
    // 备忘录全初始化为 0
    int[] memo = new int[N + 1];
    // 进行带备忘录的递归
    return dp(memo, N);
}

// 带着备忘录进行递归
int dp(int[] memo, int n) {
    // base case
    if (n == 0 || n == 1) return n;
    // 已经计算过,不用再计算了
    if (memo[n] != 0) return memo[n];
    memo[n] = dp(memo, n - 1) + dp(memo, n - 2);
    return memo[n];
}

以上就是记忆化搜索的剪枝的过程
很明显的是记忆化搜索的过程是先确定了搜索的入口dp(int[] memo, int n),使用了int[]memo来记忆递归的状态,接下来是记忆化的过程

    // 已经计算过,不用再计算了
    if (memo[n] != 0) return memo[n];

通过记忆化,一旦已经计算过状态值,可以直接返回,从而减小了冗余的计算,这样复杂度从O(2^n)减小到了O(n)这实际上是一个巨大的进步。最后才是搜索的过程

    memo[n] = dp(memo, n - 1) + dp(memo, n - 2);
    return memo[n];

这就是说自底向下和自顶向下的算法的区别
自顶向下
递归算法
自底向上:即由初始值到最终值
记忆化搜索、动态规划

相关例题

快速幂的递归解法

    public double myPow(double x, int n) {
        //快速霓算法,体现了分治和递归的思想,递归的方式
        if(n==1){
            return x;
        }
        return n>0? dfs(x,n):1/dfs(x,-n);
    }
    public double dfs(double x, int n){
        if(n==0){
            return 1;
        }
        double y=dfs(x,n/2);
        return n%2==0 ? y*y:y*y*x;
    }

快速幂的记忆化搜索的解法

    public double dfs1(double x, int n){
        if(n==0){
            return 1;
        }
        if(dp.containsKey(n)){
            return dp.get(n);
        }
        if(!dp.containsKey(n)){
            dp.put(n,n%2==0 ? dfs1(x,n/2)*dfs1(x,n/2): dfs1(x,n/2)*dfs1(x,n/2)*x);
        }
        return dp.get(n);
    }
    Map<Integer, Double> dp;
    public double myPow1(double x, int n) {
        //快速霓算法,体现了分治和递归的思想,递归的方式
        int k=Math.abs(n);
        if(n==0){
            return 1;
        }
        dp=new HashMap<>();
        dp.put(0, 1.0);
        dp.put(1,x);
        return n>0 ? dfs1(x,k):1/dfs1(x,k);
    }

最小路径和

动态规划的解法

    public int minPathSum(int[][] grid) {
        int n=grid.length;
        int m=grid[0].length;
        int [][] dp=new int[n][m];
        dp[0][0]=grid[0][0];
        for (int i = 1; i < n; i++) {
            dp[i][0]=dp[i-1][0]+grid[i][0];
        }
        for (int i = 1; i < m; i++) {
            dp[0][i]=dp[0][i-1]+grid[0][i];
        }
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < m; j++) {
                dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j];
            }
        }
        return dp[n-1][m-1];
        //记忆化搜索的方法写一下

     }

记忆化搜索的解法

public int minPathSum(int[][] grid){
        int m=grid.length;
        int n=grid[0].length;
        int [][]res=new int[m][n];
        res[0][0]=grid[0][0];
        for (int i = 1; i < n; i++) {
            res[0][i]=grid[0][i]+res[0][i-1];
        }
        for (int i = 1; i < m; i++) {
            res[i][0]=grid[i][0]+res[i-1][0];
        }
        return dfs5(res,m-1,n-1,grid);
    }
    public int dfs5(int [][]res,int i,int j,int[][] grid){
        if(i<0 ||i>=res.length ||j<0 ||j>=res[0].length){
            return 0;
        }
        if(res[i][j]>0){
            return res[i][j];
        }
        res[i][j]=Math.min(dfs5(res,i-1,j,grid),dfs5(res,i,j-1,grid))+grid[i][j];
        return res[i][j];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值