题目

image.png

思路

  • 思路一:递归暴力破解,要求(m,n)的可能性,可以先求(m-1, n)和(m, n-1)的可能性之和,依次递归
  • 思路二:备忘录,由于递归重复了子问题,可以把重复的记录下来
  • 思路三:动态规划。我们知道(0,0)的可能性,一次就知道了(0,1)和(1,0)可能性,就是递归的逆过程
  • 思路四:优化dp数组的动态规划,优化数组画图就很快解决

    代码

    1. //1. 暴力递归,超时
    2. public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    3. return recur(obstacleGrid, obstacleGrid.length - 1, obstacleGrid[0].length - 1);
    4. }
    5. public int recur(int[][] obstacleGrid, int i, int j) {
    6. if (i == 0 && j == 0 && obstacleGrid[i][j] == 0) return 1;
    7. if (i < 0 || j < 0 || obstacleGrid[i][j] == 1) return 0;
    8. return recur(obstacleGrid, i - 1, j) + recur(obstacleGrid, i, j - 1);
    9. }
    10. //2.备忘录
    11. Map<String, Integer> map = new HashMap<>();
    12. public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    13. return recur(obstacleGrid, obstacleGrid.length - 1, obstacleGrid[0].length - 1);
    14. }
    15. public int recur(int[][] obstacleGrid, int i, int j) {
    16. String key = i + "-" + j;
    17. if (map.containsKey(key)) return map.get(key);
    18. if (i == 0 && j == 0 && obstacleGrid[i][j] == 0) return 1;
    19. if (i < 0 || j < 0 || obstacleGrid[i][j] == 1) return 0;
    20. int dist = recur(obstacleGrid, i - 1, j) + recur(obstacleGrid, i, j - 1);
    21. map.put(key, dist);
    22. return dist;
    23. }
    24. //3.动态规划
    25. public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    26. //dp[i][j]表示从00到ij的所有可能性
    27. int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length];
    28. if (obstacleGrid[0][0] == 1) return 0;
    29. dp[0][0] = 1;
    30. for (int i = 1; i < obstacleGrid.length; i++) {
    31. if (obstacleGrid[i][0] == 1) {
    32. dp[i][0] = 0;
    33. } else {
    34. dp[i][0] = dp[i - 1][0];
    35. }
    36. }
    37. for (int j = 1; j < obstacleGrid[0].length; j++) {
    38. if (obstacleGrid[0][j] == 1) {
    39. dp[0][j] = 0;
    40. } else {
    41. dp[0][j] = dp[0][j - 1];
    42. }
    43. }
    44. for (int i = 1; i < obstacleGrid.length; i++) {
    45. for (int j = 1; j < obstacleGrid[0].length; j++) {
    46. if (obstacleGrid[i][j] == 0) {
    47. dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
    48. } else {
    49. dp[i][j] = 0;
    50. }
    51. }
    52. }
    53. return dp[obstacleGrid.length - 1][obstacleGrid[0].length - 1];
    54. }
    55. //3.优化dp数组的动态规划,通过观察我们可以发现只用到了前一行和当前行的前一个,所以可以优化为一维数组
    56. public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    57. //dp[j] 表示从00到ij的所有可能性
    58. int[] dp = new int[obstacleGrid[0].length];
    59. if (obstacleGrid[0][0] == 1) return 0;
    60. dp[0] = 1;
    61. for (int j = 1; j < obstacleGrid[0].length; j++) {
    62. if (obstacleGrid[0][j] == 1) {
    63. dp[j] = 0;
    64. } else {
    65. dp[j] = dp[j - 1];
    66. }
    67. }
    68. for (int i = 1; i < obstacleGrid.length; i++) {
    69. //第一列是要更新的
    70. dp[0] = obstacleGrid[i][0] == 1 ? 0 : dp[0];
    71. for (int j = 1; j < obstacleGrid[0].length; j++) {
    72. if (obstacleGrid[i][j] == 0) {
    73. dp[j] += dp[j - 1];
    74. } else {
    75. dp[j] = 0;
    76. }
    77. }
    78. }
    79. return dp[obstacleGrid[0].length - 1];
    80. }

    不同路径II