数据结构和算法从暴力到动态规划02-机器人找路问题

本文探讨了一个经典的机器人行走问题,即在一个固定长度的路径上,机器人从指定起点出发,在限定步数内到达目标点的方法数量。文章提供了三种解决方案:暴力递归、使用缓存改进的递归及动态规划。
package day_16;

/**
 * 暴力递归到动态规划02:
 * 假设有排成一行的N个位置,记为1~N,N 一定大于或等于 2
 * 开始时机器人在其中的M位置上(M 一定是 1~N 中的一个)
 * 如果机器人来到1位置,那么下一步只能往右来到2位置;
 * 如果机器人来到N位置,那么下一步只能往左来到 N-1 位置;
 * 如果机器人来到中间位置,那么下一步可以往左走或者往右走;
 * 规定机器人必须走 K 步,最终能来到P位置(P也是1~N中的一个)的方法有多少种
 * 给定四个参数 N、M、K、P,返回方法数。
 * @Author huawei
 * @Date 2021/5/12 15:26
 * @Version 1.0
 */
public class Code01_RobotWalk {
    /**
     * 首先使用暴力递归
     * @param N 一共N个位置
     * @param M 此时机器人在的位置
     * @param K 规定机器人走的步数
     * @param P 机器人想要来到的目的位置
     * @return
     */
    public static int getAllMethod(int N,int M,int K,int P){
        if(N < 1 || K < 0 || P > N || M < 0 || P < 0 || M > N ){
            return -1;
        }
        return process(M,K,N,P);

    }

    /**
     * 递归函数的意思:此时机器人的位置为M,剩余步数还剩K,目标位置P,机器人在这个时候来到目标P的方法有多少种
     * @param M 此时机器人来到的位置
     * @param K 剩余步数
     * @param N 有多少个位置
     * @param P 目标位置
     * @return
     */
    public static int process(int M,int K,int N,int P){
        // base case
        if( K == 0 ){
            // 判断当前位置是否等于目标位置,如果相等就 + 1
            return M == P ? 1 : 0;
        }else{
            // 如果不想等,有三种情况,如果走到了最左,则只有往右边走
            if(M == 1){
                return process(2,K-1,N,P);
            }else if( M == N){
                // 如果走到了最右,只有往左边走
                return process(M-1,K-1,N,P);
            }else{
                // 如果都不是,那么就是在中间,那么即可以往左边走也可以往右边走,就是两者的总和
                return process(M-1,K-1,N,P) + process(M+1,K-1,N,P);
            }
        }
    }
    public static int getAllMethod01(int cur,int aim,int N,int step){
        // 创建缓存表
        int [][] dp = new int[N + 1][step + 1];
        for(int i = 0 ; i <= N ; i++){
            for(int j = 0 ; j <= step ; j++){
                dp[i][j] = -1;
            }
        }
        return process1(cur,aim,N,step,dp);
    }

    /**
     * 利用傻缓存法来改进这个暴力递归
     * 所谓的动态规划其实就是找出暴力递归中计算相同的递归数,将每一次递归得到的值放入到一个缓存当中去,然后
     * 如果有相同的递归命中了缓存,直接去缓存中取即可
     * 缓存表的确定,在于可变长参数的范围,此题可变长参数的返回就是cur 1 - N step 0 - N
     * 所以就可以确认缓存表的变化啦
     * @param cur
     * @param aim
     * @param N
     * @param step
     * @return
     */
    public static int process1(int cur,int aim,int N,int step,int [][] dp){
        // base case
        if(step == 0){
            return cur == aim ? 1 : 0;
        }
        if(dp[cur][step] != -1){
            return dp[cur][step];
        }else{
            int ans = 0;
            if(cur == 1){
                ans = process1(2,aim,N,step - 1,dp);
            }else if(cur == N){
                ans = process1(N-1,aim,N,step-1,dp);
            }else{
                ans = process1(cur - 1, aim , N , step - 1,dp) + process1(cur + 1, aim , N ,step - 1,dp);
            }
            dp[cur][step] = ans;
            return ans;
        }
    }

    /**
     * 利用动态规划,使用状态转移来代替暴力递归
     * 犯法:找出对应的状态依赖
     * @param cur
     * @param aim
     * @param N
     * @param step
     * @return
     */
    public static int getAllMethod02(int cur,int aim,int N,int step){
        int [][] dp = new int[N + 1][step + 1];
        dp[aim][0] = 1;
        for(int i = 1 ; i <= step ; i++){
            dp[1][i] = dp[2][i-1];
            for(int 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][step];
    }


    public static void main(String[] args) {
        System.out.println(getAllMethod(3, 1, 2, 3));
        System.out.println(getAllMethod01(1, 3, 3, 2));
        System.out.println(getAllMethod01(5, 7, 7, 4));
        System.out.println(getAllMethod02(5, 7, 7, 4));
    }









}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值