28.不同路径Ⅲ(hard)

1.题目链接:980. 不同路径 III - 力扣(LeetCode)980. 不同路径 III - 在二维网格 grid 上,有 4 种类型的方格: * 1 表示起始方格。且只有一个起始方格。 * 2 表示结束方格,且只有一个结束方格。 * 0 表示我们可以走过的空方格。 * -1 表示我们无法跨越的障碍。返回在四个方向(上、下、左、右)上行走时,从起始方格到结束方格的不同路径的数目。每一个无障碍方格都要通过一次,但是一条路径中不能重复通过同一个方格。 示例 1:输入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]输出:2解释:我们有以下两条路径:1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)示例 2:输入:[[1,0,0,0],[0,0,0,0],[0,0,0,2]]输出:4解释:我们有以下四条路径: 1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)2. (0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,3)3. (0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(1,1),(0,1),(0,2),(0,3),(1,3),(2,3)4. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)示例 3:输入:[[0,1],[2,0]]输出:0解释:没有一条路能完全穿过每一个空的方格一次。请注意,起始和结束方格可以位于网格中的任意位置。 提示: * 1 <= grid.length * grid[0].length <= 20https://leetcode.cn/problems/unique-paths-iii/description/

2.题目描述:

在二维网格 grid 上,有 4 种类型的方格:​
    1 表示起始方格。且只有一个起始方格。​
    2 表示结束方格,且只有一个结束方格。​
    0 表示我们可以走过的空方格。​
    -1 表示我们无法跨越的障碍。​
    返回在四个方向(上、下、左、右)上行走时,从起始方格到结束方格的不同路径的数目。       每一个无障碍方格都要通过一次,但是一条路径中不能重复通过同一个方格。

  示例 1:​
    输入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]​
    输出:2​
    解释:我们有以下两条路径:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)​   

2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)​
    示例 2:​ 输入:[[1,0,0,0],[0,0,0,0],[0,0,0,2]]​
    输出:4​

     解释:我们有以下四条路径: ​
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)​   

2. (0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,3)​   

3. (0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(1,1),(0,1),(0,2),(0,3),(1,3),(2,3)​   

4. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)​

  示例 3:​
    输入:[[0,1],[2,0]]​
    输出:0​
    解释:
    没有一条路能完全穿过每一个空的方格一次。

请注意,起始和结束方格可以位于网格中的任意位置。

  提示:
     1 <= grid.length * grid[0].length <= 20​
3. 解法:
算法思路:
对于四个方向,我们可以定义一个二维数组 next ,大小为 4 ,每一维存储四个方向的坐标偏移量(详见代码)。题目要求到达目标位置时所有无障碍方格都存在路径中,我们可以定义一个变量记录 num  当前状态中剩余的未走过的无障碍方格个数,则当我们走到目标地点时只需要判断 num  是否0  即可。在移动时需要判断是否越界。​

递归函数设计:void dfs(vector<vector<int>>& grid, int x, int y, int num)​
参数:x,y(当前需要处理元素的坐标),num(当前剩余无障碍方格个数);​
返回值:无;
函数作用:判断当前位置的四个方向是否可以添加至当前状态,查找在满足条件下从起始方格到结束方格的不同路径的数目。

递归流程如下:
1. 递归结束条件:当前位置的元素值为 2,若此时可走的位置数量 num 的值为 0,则 cnt 的值加一;

2. 遍历四个方向,若移动后未越界,无障碍并且未被标记,则标记当前位置,并递归移动后的位置,   在回溯时撤销标记操作。

Java算法代码:

class Solution {
    boolean[][] vis;
    int m,n,step;
    int ret;
    int[]  dx= {0,0,1,-1};
    int[]  dy= {1,-1,0,0};
    public int uniquePathsIII(int[][] grid) {
        m = grid.length;n=grid[0].length;
        vis = new boolean[m][n];

        int bx =0, by =0;
        for(int i=0;i<m;i++)
            for(int j = 0;j<n;j++)
                if(grid[i][j] ==0) step++;
                else if(grid[i][j] == 1){
                    bx =i;
                    by =j;
                }
        step +=2;
        vis[bx][by] = true;
        dfs(grid,bx,by,1);
        return ret;
    }
    public void dfs(int [][] grid,int i,int j,int count){
        if(grid[i][j] ==2){
            if(count == step) ret++;
            return;
        }
        for(int k = 0;k<4;k++){
            int x = i+dx[k],y=j+dy[k];
            if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y]!= -1){
                vis[x][y] = true;
                dfs(grid, x, y, count + 1);
                vis[x][y] = false;
            }
        }
    }
}

运行结果:

递归展开:

这里的bx和by是一个临时遍历,用来记录1的所在位置。然后出来后vis[bx][by] = true;

这里有必要吗??能不能直接在循环中找到,然后直接用。实际上可以(但是不推荐,读者可以自行思考),

但是后面的一行调用的时候,还是借助了这个位置,如果不记录,(后面这里要用,还需要再次遍历得到位置,因为递归开始之前,就要算出步长(step)。

所以如果不记录,而是前面的for循环中来赋值true,后面就还需要循环。然后再次赋值(这样才能不破坏步长计算,并且不要临时变量,但是会有两次嵌套的双层for循环。

其他的细节和前面的题差不多。

---------------------------------------------------------------------------------------------------------------------------------

记住,相信你的递归函数,它可以做到!

记住,不理解时候,去尝试手动展开!

记住,逻辑展开(你不可能对所有的题目都进行手动展开)!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值