【算法】暴力递归->傻缓存->动态规划

暴力递归

尝试函数(题目涉及的参数)

if(边界条件)

return 尝试函数(改变的参数)

例:机器人走路

//N长度
//start开始的位置
//K只能走几步
//aim目的地
public static int ways1(int N, int start, int K, int aim){
    return process1(start,K,aim,N);
}


//cur当前位置
//rest剩余步数
//aim目的地
//N长度
public static int process1(int cur, int rest, int aim, int N){
    //边界条件
    //若步数已走完时
    if(rest == 0){
        //当当前位置与目的地一致,则是一种方法返回1,反之则不是返回0
        return cur == aim?1:0;
    }

    //若当前位置在最左侧时
    if(cur == 1){
        //则只能往右侧走,下一步的当前位置为2,剩余步数少一
        return process1(2,rest-1,aim,N);
    }

    //若当前位置在最右侧时
    if(cur == N){
        //则只能往左侧走,下一步的当前位置为N-1,剩余步数少一
        return process1(N-1,rest-1,aim,N);
    }

    //若当前位置在中间段时,可以往两边走
    return process1(cur-1,rest-1,aim,N)+process1(cur+1,rest-1,aim,N);
}

傻缓存

加入表[变化的参数1][变化的参数2]为函数参数

将已求过的值缓存入表中

public static int ways2(int N, int start, int K, int aim){
    //dp为缓存表
    int[][] dp = new int[N+1][K+1];

    for(int i = 0; i <=N; i++){//行
        for(int j = 0; j <=N; j++){//列
            dp[i][j] = -1;
        }
    }

    return process2(start,K,aim,N,dp);
}


public static int process2(int cur, int rest, int aim, int N, int[][] dp){
    //边界条件
    //根据上面的尝试函数可知,cur和rest参数一直在改变,则表中的参数则为cur和rest
    //若dp表对应的参数曾被算过时,由于之前被存储进去过,则dp表中必含有该参数不是上面方法赋值-1的值
    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 = process2(2,rest-1,aim,N,dp);
    }else if(cur == N){
        ans = process2(N-1,rest-1,aim,N,dp);
    }else{
        ans = process1(cur-1,rest-1,aim,N)+process1(cur+1,rest-1,aim,N,dp);
    }
    
    //将ans值缓存放入dp中
    dp[cur][rest] = ans;
    return ans;
}

动态规划(记住已求过的解,减少重复计算)

定义表[变化的参数1][变化的参数2]

根据尝试函数画出表图,把原来递归函数用表来代替

例:N:123,start:2,aim:3,K:3,则求坐标(2,3)的值

return process1(cur-1,rest-1,aim,N)

+process1(cur+1,rest-1,aim,N);

if(rest == 0){

  return cur==aim?1:0;

}

cur\rest

0

123
0××××

if(cur == 1){

  return process1(2,rest-1,aim,N);

}

10

0

依赖于

(2,1-1)

10
20

1

依赖于

(2-1,1-1)

+(2+1,1-1)

0

※求

2

if(cur == N){

  return process1(N-1,rest-1,aim,N);

}

31

0

依赖于

(3-1,1-1)

10
public static int ways3(int N, int start, int P, int K){
    //定义表
    int[][] dp = new int[N+1][K+1];
    
    //根据上面的尝试函数可知
    /*
        if(rest == 0){
        return cur == aim?1:0;
        }
    */
    dp[P][0] = 1;//dp[除P外][0] = 0
    
    for(int rest = 1; rest <= K; rest++){//列
        /*
            if(cur == 1){
                return process1(2,rest-1,aim,N);
            }
        */
        dp[1][rest] = dp[2][rest-1];
        
        for(int cur = 2; cur < N; cur++){//行
            //return process1(cur-1,rest-1,aim,N)+process1(cur+1,rest-1,aim,N);
            dp[cur][rest] = dp[cur-1][rest-1] + dp[cur+1][rest-1];
        }

        /*
            if(cur == N){
                return process1(N-1,rest-1,aim,N);
            }
        */
        dp[N][rest] = dp[N-1][rest-1];
    }

    return dp[start][K];
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头的少女

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值