迷路的机器人(递归回溯+动态规划两个方法实现)

题目:

设想有个机器人坐在一个网格的左上角,网格 r 行 c 列。机器人只能向下或向右移动,但不能走到一些被禁止的网格(有障碍物)。设计一种算法,寻找机器人从左上角移动到右下角的路径。

示例:

输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: [[0,0],[0,1],[0,2],[1,2],[2,2]]
解释: 
输入中标粗的位置即为输出表示的路径,即
0行0列(左上角) -> 0行1列 -> 0行2列 -> 1行2列 -> 2行2列(右下角)

解题思路:动态规划 

1.先找到可行的路径,不可达的坐标点 dp=0

2.如果终点的dp不为0,说明存在可达的路径

3.那么就从终点往回走,找到可以到达起点的路径,每走一步都要将坐标添加到res数组中

4.由于是从后往前的,所以要将res进行反转

源代码如下:

class Solution {
public:
    vector<vector<int>> pathWithObstacles(vector<vector<int>>& obstacleGrid) {
        vector<vector<int>> res;
        if(obstacleGrid.size()==0) return res;//矩阵为空,直接返回空数组
        int m=obstacleGrid.size();
        int n=obstacleGrid[0].size();
        //矩阵的起点和终点不可达,则返回空数组
        if(obstacleGrid[0][0]==1||obstacleGrid[m-1][n-1]==1) return res;
        int dp[m][n];//定义动态规划数组
        dp[0][0]=1;//起点位置可达,置为1
        //先找第一列的元素是否可达
        for(int i=1;i<m;i++)
        {
            //不可达,dp置为0
            if(obstacleGrid[i][0]==1) dp[i][0]=0;
            //可达,则dp等于上一行的
            else
            {
                dp[i][0]=dp[i-1][0];
            }
        }
        //找第一行的元素
        for(int i=1;i<n;i++)
        {
            if(obstacleGrid[0][i]==1) dp[0][i]=0;
            else
            {
                dp[0][i]=dp[0][i-1];
            }
        }
        //其他剩余元素
        for(int i=1;i<m;i++)
        {
            for(int j=1;j<n;j++)
            {
                if(obstacleGrid[i][j]==1) dp[i][j]=0;
                else
                {
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        //如果终点的dp=0,说明不能到达终点,则返回空数组
        if(dp[m-1][n-1]==0) return res;
        //以下情况是已经找到路径了,只需要把路径添加到res中
        //从后往前找可以到达的点
        int i=m-1,j=n-1;
        while(i!=0||j!=0)
        {
            res.push_back({i,j});
       		//往上走
            int up=0;
            if(i>0) up=dp[i-1][j];
            //往左走
            int left=0;
            if(j>0) left=dp[i][j-1];
            //哪个dp值不为0,则走哪个方向
            if(up>=left) i--;
            else j--;
        }
        //最后把起点添加到数组中
        res.push_back({0,0});
        //再将数组翻转,就是正确顺序了
        reverse(res.begin(),res.end());
        return res;
    }
};

 解题思路:回溯

需要注意的是,要添加一个访问数组,标记该坐标是否已经被访问过。详解看代码

源代码如下:

class Solution {
public:
    bool isfind=false;//是否已经找到路径
    void dfs(vector<vector<int>>& obstacleGrid,vector<vector<int>>& res,vector<vector<bool>>& visited,int m,int n,int i,int j)
    {
        //如果下标i和j越界
        //如果已经找到路径(isfind==true)
        //如果当前坐标有障碍物
        //如果当前坐标已访问
        //遇到以上这些情况 直接返回
        if(i<0||i>=m||j<0||j>=n||isfind||obstacleGrid[i][j]==1||visited[i][j]) return;
        //当前坐标已经到达终点,说明找到路径了
        if(i==m-1&&j==n-1)
        {
            isfind=true;//isfind置为真
            res.push_back({i,j});//将终点添加到数组中
            //并返回
            return;
        }
		//其余正常情况,每遍历一个坐标,就将该坐标标记为已访问
        visited[i][j]=true;
        res.push_back({i,j});//坐标添加到数组中
        //递归,往下走
        dfs(obstacleGrid,res,visited,m,n,i+1,j);
        //递归,往右走
        dfs(obstacleGrid,res,visited,m,n,i,j+1);
		//回溯
        if(!isfind) res.pop_back();
    }
    vector<vector<int>> pathWithObstacles(vector<vector<int>>& obstacleGrid) {
        vector<vector<int>> res;
        int m=obstacleGrid.size();
        int n=obstacleGrid[0].size();
        if(obstacleGrid.size()==0) return res;
        //标记当前坐标是否已经访问过,初始值都为false
        vector<vector<bool>> visited(m, vector<bool>(n, false));
        if(obstacleGrid[0][0]==1||obstacleGrid[m-1][n-1]==1) return res;
        dfs(obstacleGrid,res,visited,m,n,0,0);

        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
递归回溯动态规划都是常用的问题求解方法,它们在不同的场景下有不同的应用。 递归(Recursion)是一种通过将问题分解为更小的子问题来求解的方法递归函数会重复调用自身,直到达到某个终止条件。递归通常用于解决问题的定义是自身的情况,例如计算斐波那契数列、求解二叉树的深度等。递归实现简单直观,但在某些情况下可能会导致效率低下或者堆栈溢出的问题。 回溯(Backtracking)是一种通过尝试所有可能的情况来求解问题的方法回溯算法通常用于求解排列组合、搜索问题,如八皇后问题、组合总和等。回溯算法通过遍历所有可能的选择并进行回退,以找到所有满足条件的解。回溯算法可以通过剪枝操作来减少不必要的尝试,提高效率。 动态规划(Dynamic Programming)是一种通过将问题划分为若干个重叠子问题,并保存子问题的解来避免重复计算的方法动态规划通常用于求解最优化问题,如最长公共子序列、最短路径、背包问题等。动态规划算法通过状态转移方程和边界条件来确定子问题之间的关系,并按照一定的计算顺序求解子问题,最终得到原问题的解。动态规划算法的时间复杂度通常较低,可以大大提高算法的效率。 总结来说,递归是一种问题分解的方法回溯是一种穷举搜索的方法动态规划是一种优化求解的方法。它们在不同的问题场景下有着各自的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值