[Leetcode学习-java]Unique Paths I ~ III

这类问题都是DP的简单用法:

相关算法:

P1002-过河卒:https://blog.csdn.net/qq_28033719/article/details/106261183


Unique Paths I

问题:

难度:easy

文章链接:https://blog.csdn.net/qq_28033719/article/details/107033638


Unique Paths II

问题:

难度:medium

说明:

输入一个二维数组 int[][] ,机器人只会往右往左走,然后多了石头,机器人不能通过石头,0 代表没有石头,1 代表有石头。

题目连接:https://leetcode.com/problems/unique-paths-ii/

输入案例:

Input: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
Output: 2
Explanation: There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right

我的代码:

其实也是和过河卒一样,过河卒好歹是一个马,这只是个石头更加简单。

二维数组做法:

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int x = obstacleGrid.length;
        int y = obstacleGrid[0].length;
        int[][] dp = new int[x][y];
        for(int i = 0;i < x;i ++) 
            if(obstacleGrid[i][0] != 1) dp[i][0] = 1;
            else break;
        for(int i = 0;i < y;i ++) 
            if(obstacleGrid[0][i] != 1) dp[0][i] = 1;
            else break;
        
        for(int i = 1;i < x;i ++) 
            for(int j = 1;j < y;j ++) 
                if(obstacleGrid[i][j] != 1) dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        return dp[x - 1][y - 1];
    }
}

改成一维数组,其实也就是减少空间复杂度:

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int x = obstacleGrid.length;
        int y = obstacleGrid[0].length;
        int[] dp = new int[y];
        for(int i = 0;i < y;i ++) 
            if(obstacleGrid[0][i] != 1) dp[i] = 1;
            else break;
        
        boolean open = obstacleGrid[0][0] != 1; // 做 X 轴石头标记
        for(int i = 1;i < x;i ++) {
            if(open) dp[0] = (open = obstacleGrid[i][0] != 1) ? 1 : 0;
            for(int j = 1;j < y;j ++)
                dp[j] = obstacleGrid[i][j] != 1 ? dp[j] + dp[j - 1] : 0;
        }
        return dp[y - 1];
    }
}

也可以用输入给出来的那个数组,区分下,石头 路径 两个数量区别就行,尤其是开头和开头边界的数字

class Solution {
    public int uniquePathsWithObstacles(int[][] ob) {
        int x = ob.length;
        int y = ob[0].length;
        boolean block = ob[0][0] == 1; // 要区分开头是否阻塞了
        for(int i = 0;i < x;i ++)
            if(ob[i][0] != 1) ob[i][0] = 1;
            else
                for(;i < x;i ++) ob[i][0] = 0; // 注意边界的阻塞是全部
        for(int i = 1;i < y;i ++)
            if(!block && ob[0][i] != 1) ob[0][i] = 1;
            else
                for(;i < y;i ++) ob[0][i] = 0; // 注意边界的阻塞是全部

        for(int i = 1;i < x;i ++)
            for(int j = 1;j < y;j ++)
                ob[i][j] = ob[i][j] != 1 ? ob[i - 1][j] + ob[i][j - 1] : 0;
        return ob[x - 1][y - 1];
    }
}

Unique Paths III

问题:

难度:hard

说明:

输入一个二维数组 int[][] ,机器人能够上下左右行动,然后-1表示不能走,1 表示开始位置, 2表示结束位置,机器人要把地图为 0 的地方走一遍,返回多少种走法。

题目连接:https://leetcode.com/problems/unique-paths-iii/

输入范围:

  1. 1 <= grid.length * grid[0].length <= 20

输入案例:

Example 1:
Input: [[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
Output: 2
Explanation: We have the following two paths: 
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)

Example 2:
Input: [[1,0,0,0],[0,0,0,0],[0,0,0,2]]
Output: 4
Explanation: We have the following four paths: 
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)

Example 3:
Input: [[0,1],[2,0]]
Output: 0
Explanation: 
There is no path that walks over every empty square exactly once.
Note that the starting and ending square can be anywhere in the grid.

我的代码:

这个的话看题目看了好久,原来要全部 0 都走一遍,怪不得结果解析那么复杂。

具体还是做 dp 不过是 dfs 做法,幸好输入面积 20 以内,所以不会太耗时。

class Solution {
    private static int x = 0;
    private static int y = 0;
    private static int count = 0;
    
    public int uniquePathsIII(int[][] grid) {
        count = 1;
        x = grid.length;
        y = grid[0].length;
        int bi = 0, bj = 0;
        
        for(int i = 0;i < x;i ++) // 统计需要浏览的 0 数量
            for(int j = 0;j < y;j ++) if(grid[i][j] == 0) count ++;
        
        A:for(; bi < x; bi ++) // 找开始
            for(bj = 0; bj < y; bj ++) if(grid[bi][bj] == 1) break A;

        return recurtion(bi, bj, grid, 0);
    }

    public int recurtion(int bi, int bj, int[][] grid, int c) {
        if(!(bi < 0 || bi == x || bj < 0 || bj == y)) {
            if(grid[bi][bj] == 0 || grid[bi][bj] == 1) {
                grid[bi][bj] = 5; // 当前表示已经浏览过标记
                int cc = c + 1;
                int res = recurtion(bi - 1, bj, grid, cc) 
                    + recurtion(bi + 1, bj, grid, cc) 
                    + recurtion(bi, bj - 1, grid, cc) 
                    + recurtion(bi, bj + 1, grid, cc);
                grid[bi][bj] = 0; // 退出浏览重置 0
                return res;
            } else if(grid[bi][bj] == 2 && c == count) return 1; // 到达终点并且全部 0 浏览
        } return 0;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_28033719/article/details/109983289