「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
给定一个矩阵matrix,值有正、负、0。蛇可以空降到最左列的任何一个位置,初始增长值是0。蛇每一步可以选择右上、右、右下三个方向的任何一个前进。沿途的数字累加起来,作为增长值;但是蛇一旦增长值为负数,就会死去。蛇有一种能力,可以使用一次:把某个格子里的数变成相反数。蛇可以走到任何格子的时候停止。返回蛇能获得的最大增长值。
一、分析
f(i,j)
初步分析:蛇从最优的最左边到达某个位置时,获得的最大增长值,在每个点上获得值求max
进一步分析:蛇有一种能力,是否使用这种能力。
f(i,j):返回两个值
- 蛇从最优的某个左侧位置开始,走到(i,j)位置停,中途一次也没用这种能力,获得的最大增长值
- 蛇从最优的某个左侧位置开始,走到(i,j)位置停,中途使用了一次这种能力,获得的最大增长值
最终答案:max(2*M*N) M*N的格子,每个格子返回2种答案,最后求Max
尝试模型
左上、左边、左下 => 当前位置,从三种情况下蛇可以到达当前位置
左边所有可能性中一次能力也没用和用了一次能力的最好情况
如果蛇从某一个最左列,且最优的空降点降落,不用能力,怎么都到不了(i,j),那么no = -1
如果蛇从某一个最左列,且最优的空降点降落,用了一次能力,怎么都到不了(i,j),那么yes = -1
当前的no:你之前并且你现在一次能力也没用
当前的yes:之前用了或者当前用,这两种情况
二、实现
public static int walk(int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return 0;
}
int ans = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
Info cur = f(matrix, i, j);
ans = Math.max(ans, Math.max(cur.no, cur.yes));
}
}
return ans;
}
public static class Info {
public int no;
public int yes;
public Info(int n, int y) {
no = n;
yes = y;
}
}
public static Info f(int[][] matrix, int i, int j) {
if (j == 0) { // 最左列
int no = Math.max(matrix[i][0], -1);
int yes = Math.max(-matrix[i][0], -1);
return new Info(no, yes);
}
// j > 0 不在最左列
int preNo = -1;
int preYes = -1;
Info pre = f(matrix, i, j - 1);
preNo = Math.max(pre.no, preNo);
preYes = Math.max(pre.yes, preYes);
if (i > 0) {
pre = f(matrix, i - 1, j - 1);
preNo = Math.max(pre.no, preNo);
preYes = Math.max(pre.yes, preYes);
}
if (i < matrix.length - 1) {
pre = f(matrix, i + 1, j - 1);
preNo = Math.max(pre.no, preNo);
preYes = Math.max(pre.yes, preYes);
}
int no = preNo == -1 ? -1 : (Math.max(-1, preNo + matrix[i][j]));
// 能力只有一次,是之前用的!
int p1 = preYes == -1 ? -1 : (Math.max(-1, preYes + matrix[i][j]));
// 能力只有一次,就当前用!
int p2 = preNo == -1 ? -1 : (Math.max(-1, preNo - matrix[i][j]));
int yes = Math.max(Math.max(p1, p2), -1);
return new Info(no, yes);
}
三、总结
感觉写代码跟咬文嚼字似的,你怎么假设的,就怎么写,代码就写出来了!