题目链接

最大得分的路径数目

题目描述

image.png

实现代码

dfs递归遍历实现代码:(超时)

  1. class Solution {
  2. int max = 0;
  3. int count = 0;
  4. public int[] pathsWithMaxScore(List<String> board) {
  5. int n = board.size();
  6. int[][] arr = new int[n][n];
  7. for (int i = 0; i < n; i++) {
  8. String str = board.get(i);
  9. for (int j = 0; j < n; j++) {
  10. char c = str.charAt(j);
  11. if(c >= '0' && c <= '9') {
  12. arr[i][j] = c - '0';
  13. } else if(c == 'S'){
  14. arr[i][j] = 0;
  15. } else {
  16. arr[i][j] = Integer.MAX_VALUE;
  17. }
  18. }
  19. }
  20. dfs(arr, n, n - 1, n - 1, 0);
  21. return new int[]{max, count};
  22. }
  23. private void dfs(int[][] arr, int n, int curX, int curY, int curMax) {
  24. if (curX < 0 || curX > n - 1) {
  25. return;
  26. }
  27. if (curY < 0 || curY > n - 1) {
  28. return;
  29. }
  30. if (curX == 0 && curY == 0) {
  31. if (curMax == max) {
  32. count++;
  33. } else if (curMax > max) {
  34. max = curMax;
  35. count = 1;
  36. }
  37. return;
  38. }
  39. if(arr[curX][curY] == Integer.MAX_VALUE) {
  40. return;
  41. }
  42. curMax += arr[curX][curY];
  43. dfs(arr, n, curX-1, curY, curMax);
  44. dfs(arr, n, curX, curY-1, curMax);
  45. dfs(arr, n, curX-1, curY-1, curMax);
  46. }
  47. }

动态规划思想:

  1. class Solution {
  2. int INF = Integer.MIN_VALUE;
  3. int mod = (int)1e9+7;
  4. int n;
  5. public int[] pathsWithMaxScore(List<String> board) {
  6. n = board.size();
  7. // 将 board 转存成二维数组
  8. char[][] cs = new char[n][n];
  9. for (int i = 0; i < n; i++) {
  10. cs[i] = board.get(i).toCharArray();
  11. }
  12. // f(i) 代表从右下角到位置 i 的最大得分
  13. int[] f = new int[n * n];
  14. // f(i) 代表从右下角到位置 i 并取到最大得分的方案数量
  15. int[] g = new int[n * n];
  16. for (int i = n - 1; i >= 0; i--) {
  17. for (int j = n - 1; j >= 0; j--) {
  18. int idx = getIdx(i, j);
  19. // 一个初始化的状态,如果是在最后一格(起点):
  20. // g[idx] = 1 : 代表到达起点的路径只有一条,这样我们就有了一个「有效值」可以滚动下去
  21. // f[idx] = 0 : 代表在起点得分为 0
  22. if (i == n - 1 && j == n - 1) {
  23. g[idx] = 1;
  24. continue;
  25. }
  26. // 如果该位置是「障碍点」,那么对应状态为:
  27. // g[idx] = 0 : 「障碍点」不可访问,路径为 0
  28. // f[idx] = INF : 「障碍点」不可访问,得分为无效值
  29. if (cs[i][j] == 'X') {
  30. f[idx] = INF;
  31. continue;
  32. }
  33. // 如果是第一个格子(终点),这时候位置得分为 0
  34. int val = (i == 0 && j == 0) ? 0 : cs[i][j] - '0';
  35. // u 代表当前位置的「最大得分」;t 代表取得最大得分的「方案数」
  36. int u = INF, t = 0;
  37. // 如果「下方格子」合法,尝试从「下方格子」进行转移
  38. if (i + 1 < n) {
  39. int cur = f[getIdx(i + 1, j)] + val;
  40. int cnt = g[getIdx(i + 1, j)];
  41. int[] res = update(cur, cnt, u, t);
  42. u = res[0]; t = res[1];
  43. }
  44. // 如果「右边格子」合法,尝试从「右边格子」进行转移
  45. if (j + 1 < n) {
  46. int cur = f[getIdx(i, j + 1)] + val;
  47. int cnt = g[getIdx(i, j + 1)];
  48. int[] res = update(cur, cnt, u, t);
  49. u = res[0]; t = res[1];
  50. }
  51. // 如果「右下角格子」合法,尝试从「右下角格子」进行转移
  52. if (i + 1 < n && j + 1 < n) {
  53. int cur = f[getIdx(i + 1, j + 1)] + val;
  54. int cnt = g[getIdx(i + 1, j + 1)];
  55. int[] res = update(cur, cnt, u, t);
  56. u = res[0]; t = res[1];
  57. }
  58. // 更新 dp 值
  59. f[idx] = u < 0 ? INF : u;
  60. g[idx] = t;
  61. }
  62. }
  63. // 构造答案
  64. int[] ans = new int[2];
  65. // 如果终点不可达(动规值为 INF)时,写入 0
  66. ans[0] = f[getIdx(0, 0)] == INF ? 0 : f[getIdx(0, 0)];
  67. // 如果终点不可达(动规值为 INF)时,写入 0
  68. ans[1] = f[getIdx(0, 0)] == INF ? 0 : g[getIdx(0, 0)];
  69. return ans;
  70. }
  71. // 更新 dp 值
  72. int[] update(int cur, int cnt, int u, int t) {
  73. // 起始答案为 [u, t] : u 为「最大得分」,t 为最大得分的「方案数」
  74. int[] ans = new int[]{u, t};
  75. // 如果当前值大于 u,更新「最大得分」和「方案数」
  76. if (cur > u) {
  77. ans[0] = cur;
  78. ans[1] = cnt;
  79. // 如果当前值等于 u,增加「方案数」
  80. } else if (cur == u && cur != INF) {
  81. ans[1] += cnt;
  82. }
  83. ans[1] %= mod;
  84. return ans;
  85. }
  86. // 二维坐标 (x,y) 与 idx 的相互转换
  87. int getIdx(int x, int y) {
  88. return x * n + y;
  89. }
  90. int[] parseIdx(int idx) {
  91. return new int[]{idx / n, idx % n};
  92. }
  93. }

在动态规划的基础上对复杂度进行优化(使用结构体):

  1. class Solution {
  2. final int MOD = 1000000007;
  3. public int[] pathsWithMaxScore(List<String> board) {
  4. int n = board.size();
  5. //将给的字符表转化成字符矩阵
  6. char[][] map = new char[n][n];
  7. for(int i = 0; i < n; i++){
  8. map[i] = board.get(i).toCharArray();
  9. }
  10. //初始化边界条件都要为0
  11. Info[][] f = new Info[2][n+1];
  12. for(int i = 0; i <= n; i++){
  13. f[0][i] = new Info(0,0);
  14. f[1][i] = new Info(0,0);
  15. }
  16. int last = 0,now = 1;
  17. for(int i = n-1;i >= 0; i--){
  18. last = now;
  19. now = 1 - now;
  20. for(int j = n-1; j >= 0; j--){
  21. if(i == n-1 && j == n-1) {
  22. //将起始分数设为1是为区分围墙全面堵死情况
  23. // 因为在右,右下,下三块均为0,说明堵死,就是现在这一块有分数也不能加
  24. //但是起始点三块都0,必须区分,起始要加,其他情况不加
  25. f[now][j] = new Info(1,1);
  26. }else
  27. if(i == 0 && j == 0){
  28. f[now][j] = MaxInfo(f[last][j],f[last][j+1],f[now][j+1]);
  29. }else
  30. if(map[i][j] == 'X'){
  31. f[now][j] = new Info(0,0);
  32. }else{
  33. f[now][j] = MaxInfo(f[last][j],f[last][j+1],f[now][j+1]);
  34. f[now][j].maxScores += (f[now][j].maxScores == 0 ) ? 0 :map[i][j] - '0';
  35. }
  36. }
  37. }
  38. //如果最后结果不为0,也就是没有全面封死,要把起始1减掉
  39. int maxScore = f[now][0].maxScores != 0 ? f[now][0].maxScores-1 : 0;
  40. return new int[]{maxScore,f[now][0].maxways};
  41. }
  42. public Info MaxInfo(Info a,Info b,Info c){
  43. int maxScore = 0;
  44. int maxway = 0;
  45. maxScore = Math.max(a.maxScores,Math.max(b.maxScores,c.maxScores));
  46. if(maxScore == a.maxScores) maxway += a.maxways;
  47. if(maxScore == b.maxScores) maxway += b.maxways;
  48. if(maxScore == c.maxScores) maxway += c.maxways;
  49. return new Info(maxScore % MOD,maxway % MOD);
  50. }
  51. class Info{
  52. int maxScores;
  53. int maxways;
  54. public Info(int maxScores,int maxways){
  55. this.maxScores = maxScores;
  56. this.maxways = maxways;
  57. }
  58. }
  59. }