题目链接
题目描述
实现代码
dfs递归遍历实现代码:(超时)
class Solution {
int max = 0;
int count = 0;
public int[] pathsWithMaxScore(List<String> board) {
int n = board.size();
int[][] arr = new int[n][n];
for (int i = 0; i < n; i++) {
String str = board.get(i);
for (int j = 0; j < n; j++) {
char c = str.charAt(j);
if(c >= '0' && c <= '9') {
arr[i][j] = c - '0';
} else if(c == 'S'){
arr[i][j] = 0;
} else {
arr[i][j] = Integer.MAX_VALUE;
}
}
}
dfs(arr, n, n - 1, n - 1, 0);
return new int[]{max, count};
}
private void dfs(int[][] arr, int n, int curX, int curY, int curMax) {
if (curX < 0 || curX > n - 1) {
return;
}
if (curY < 0 || curY > n - 1) {
return;
}
if (curX == 0 && curY == 0) {
if (curMax == max) {
count++;
} else if (curMax > max) {
max = curMax;
count = 1;
}
return;
}
if(arr[curX][curY] == Integer.MAX_VALUE) {
return;
}
curMax += arr[curX][curY];
dfs(arr, n, curX-1, curY, curMax);
dfs(arr, n, curX, curY-1, curMax);
dfs(arr, n, curX-1, curY-1, curMax);
}
}
动态规划思想:
class Solution {
int INF = Integer.MIN_VALUE;
int mod = (int)1e9+7;
int n;
public int[] pathsWithMaxScore(List<String> board) {
n = board.size();
// 将 board 转存成二维数组
char[][] cs = new char[n][n];
for (int i = 0; i < n; i++) {
cs[i] = board.get(i).toCharArray();
}
// f(i) 代表从右下角到位置 i 的最大得分
int[] f = new int[n * n];
// f(i) 代表从右下角到位置 i 并取到最大得分的方案数量
int[] g = new int[n * n];
for (int i = n - 1; i >= 0; i--) {
for (int j = n - 1; j >= 0; j--) {
int idx = getIdx(i, j);
// 一个初始化的状态,如果是在最后一格(起点):
// g[idx] = 1 : 代表到达起点的路径只有一条,这样我们就有了一个「有效值」可以滚动下去
// f[idx] = 0 : 代表在起点得分为 0
if (i == n - 1 && j == n - 1) {
g[idx] = 1;
continue;
}
// 如果该位置是「障碍点」,那么对应状态为:
// g[idx] = 0 : 「障碍点」不可访问,路径为 0
// f[idx] = INF : 「障碍点」不可访问,得分为无效值
if (cs[i][j] == 'X') {
f[idx] = INF;
continue;
}
// 如果是第一个格子(终点),这时候位置得分为 0
int val = (i == 0 && j == 0) ? 0 : cs[i][j] - '0';
// u 代表当前位置的「最大得分」;t 代表取得最大得分的「方案数」
int u = INF, t = 0;
// 如果「下方格子」合法,尝试从「下方格子」进行转移
if (i + 1 < n) {
int cur = f[getIdx(i + 1, j)] + val;
int cnt = g[getIdx(i + 1, j)];
int[] res = update(cur, cnt, u, t);
u = res[0]; t = res[1];
}
// 如果「右边格子」合法,尝试从「右边格子」进行转移
if (j + 1 < n) {
int cur = f[getIdx(i, j + 1)] + val;
int cnt = g[getIdx(i, j + 1)];
int[] res = update(cur, cnt, u, t);
u = res[0]; t = res[1];
}
// 如果「右下角格子」合法,尝试从「右下角格子」进行转移
if (i + 1 < n && j + 1 < n) {
int cur = f[getIdx(i + 1, j + 1)] + val;
int cnt = g[getIdx(i + 1, j + 1)];
int[] res = update(cur, cnt, u, t);
u = res[0]; t = res[1];
}
// 更新 dp 值
f[idx] = u < 0 ? INF : u;
g[idx] = t;
}
}
// 构造答案
int[] ans = new int[2];
// 如果终点不可达(动规值为 INF)时,写入 0
ans[0] = f[getIdx(0, 0)] == INF ? 0 : f[getIdx(0, 0)];
// 如果终点不可达(动规值为 INF)时,写入 0
ans[1] = f[getIdx(0, 0)] == INF ? 0 : g[getIdx(0, 0)];
return ans;
}
// 更新 dp 值
int[] update(int cur, int cnt, int u, int t) {
// 起始答案为 [u, t] : u 为「最大得分」,t 为最大得分的「方案数」
int[] ans = new int[]{u, t};
// 如果当前值大于 u,更新「最大得分」和「方案数」
if (cur > u) {
ans[0] = cur;
ans[1] = cnt;
// 如果当前值等于 u,增加「方案数」
} else if (cur == u && cur != INF) {
ans[1] += cnt;
}
ans[1] %= mod;
return ans;
}
// 二维坐标 (x,y) 与 idx 的相互转换
int getIdx(int x, int y) {
return x * n + y;
}
int[] parseIdx(int idx) {
return new int[]{idx / n, idx % n};
}
}
在动态规划的基础上对复杂度进行优化(使用结构体):
class Solution {
final int MOD = 1000000007;
public int[] pathsWithMaxScore(List<String> board) {
int n = board.size();
//将给的字符表转化成字符矩阵
char[][] map = new char[n][n];
for(int i = 0; i < n; i++){
map[i] = board.get(i).toCharArray();
}
//初始化边界条件都要为0
Info[][] f = new Info[2][n+1];
for(int i = 0; i <= n; i++){
f[0][i] = new Info(0,0);
f[1][i] = new Info(0,0);
}
int last = 0,now = 1;
for(int i = n-1;i >= 0; i--){
last = now;
now = 1 - now;
for(int j = n-1; j >= 0; j--){
if(i == n-1 && j == n-1) {
//将起始分数设为1是为区分围墙全面堵死情况
// 因为在右,右下,下三块均为0,说明堵死,就是现在这一块有分数也不能加
//但是起始点三块都0,必须区分,起始要加,其他情况不加
f[now][j] = new Info(1,1);
}else
if(i == 0 && j == 0){
f[now][j] = MaxInfo(f[last][j],f[last][j+1],f[now][j+1]);
}else
if(map[i][j] == 'X'){
f[now][j] = new Info(0,0);
}else{
f[now][j] = MaxInfo(f[last][j],f[last][j+1],f[now][j+1]);
f[now][j].maxScores += (f[now][j].maxScores == 0 ) ? 0 :map[i][j] - '0';
}
}
}
//如果最后结果不为0,也就是没有全面封死,要把起始1减掉
int maxScore = f[now][0].maxScores != 0 ? f[now][0].maxScores-1 : 0;
return new int[]{maxScore,f[now][0].maxways};
}
public Info MaxInfo(Info a,Info b,Info c){
int maxScore = 0;
int maxway = 0;
maxScore = Math.max(a.maxScores,Math.max(b.maxScores,c.maxScores));
if(maxScore == a.maxScores) maxway += a.maxways;
if(maxScore == b.maxScores) maxway += b.maxways;
if(maxScore == c.maxScores) maxway += c.maxways;
return new Info(maxScore % MOD,maxway % MOD);
}
class Info{
int maxScores;
int maxways;
public Info(int maxScores,int maxways){
this.maxScores = maxScores;
this.maxways = maxways;
}
}
}