class Solution {
public:
long long maxPoints(vector<vector<int>>& points) {
}
};
1937. 扣分后的最大得分
给你一个 m x n
的整数矩阵 points
(下标从 0 开始)。一开始你的得分为 0
,你想最大化从矩阵中得到的分数。
你的得分方式为:每一行 中选取一个格子,选中坐标为 (r, c)
的格子会给你的总得分 增加 points[r][c]
。
然而,相邻行之间被选中的格子如果隔得太远,你会失去一些得分。对于相邻行 r
和 r + 1
(其中 0 <= r < m - 1
),选中坐标为 (r, c1)
和 (r + 1, c2)
的格子,你的总得分 减少 abs(c1 - c2)
。
请你返回你能得到的 最大 得分。
abs(x)
定义为:
x >= 0
,那么值为 x
。x < 0
,那么值为 -x
。
示例 1:
输入:points = [[1,2,3],[1,5,1],[3,1,1]] 输出:9 解释: 蓝色格子是最优方案选中的格子,坐标分别为 (0, 2),(1, 1) 和 (2, 0) 。 你的总得分增加 3 + 5 + 3 = 11 。 但是你的总得分需要扣除 abs(2 - 1) + abs(1 - 0) = 2 。 你的最终得分为 11 - 2 = 9 。
示例 2:
输入:points = [[1,5],[2,3],[4,2]] 输出:11 解释: 蓝色格子是最优方案选中的格子,坐标分别为 (0, 1),(1, 1) 和 (2, 0) 。 你的总得分增加 5 + 3 + 4 = 12 。 但是你的总得分需要扣除 abs(1 - 1) + abs(1 - 0) = 1 。 你的最终得分为 12 - 1 = 11 。
提示:
m == points.length
n == points[r].length
1 <= m, n <= 105
1 <= m * n <= 105
0 <= points[r][c] <= 105
原站题解
python3 解法, 执行用时: 828 ms, 内存消耗: 39.1 MB, 提交时间: 2023-07-01 14:03:37
''' 对于所有上一行左边的数,都是加上它的坐标减去自己的坐标; 对于上一行所有右边的数,都是减去它的坐标加上自己的坐标; 分别求最大值即可。 ''' class Solution: def maxPoints(self, points: List[List[int]]) -> int: m = len(points) n = len(points[0]) dp = points[0] for i in range(1, m): new_dp = list(dp) left_max = -inf right_max = -inf for j in range(n): left_max = max(left_max, dp[j] + j) right_max = max(right_max, dp[n-1-j] - (n - 1 - j)) new_dp[j] = max(left_max - j + points[i][j], new_dp[j]) new_dp[n-1-j] = max((n - 1 - j) + right_max + points[i][n-1-j], new_dp[n-1-j]) dp = new_dp return max(dp)
java 解法, 执行用时: 8 ms, 内存消耗: 66.2 MB, 提交时间: 2023-07-01 14:02:57
/** * dp[i][j]表示第i行第j列的元素所能得到的最大分数 * dp[i][j] = max(dp[i - 1][k] + abs(k - j)) * **/ class Solution { public long maxPoints(int[][] points) { int m = points.length; int n = points[0].length; long[] dp = new long[n]; for (int i = 0; i < m; i++) { long[] cur = new long[n + 1]; long lmax = 0; for (int j = 0; j < n; j++) { lmax = Math.max(lmax - 1, dp[j]); cur[j] = lmax; } long rmax = 0; for (int j = n - 1; j >= 0; j--) { rmax = Math.max(rmax - 1, dp[j]); cur[j] = Math.max(cur[j], rmax); } for (int j = 0; j < n; j++) { dp[j] = cur[j] + points[i][j]; } } long ans = 0; for (int j = 0; j < n; j++) { ans = Math.max(ans, dp[j]); } return ans; } }
golang 解法, 执行用时: 192 ms, 内存消耗: 18.4 MB, 提交时间: 2023-07-01 14:00:53
func maxPoints(points [][]int) int64 { ans := 0 n := len(points[0]) f := make([][2]int, n) // f[i][j] 前i行中,第i行选择points[i][j]的最大得分 sufMax := make([]int, n) // 后缀最大值 for i, row := range points { if i == 0 { for j, v := range row { ans = max(ans, v) f[j][0] = v + j f[j][1] = v - j } } else { preMax := math.MinInt32 for j, v := range row { preMax = max(preMax, f[j][0]) res := max(v-j+preMax, v+j+sufMax[j]) // 左侧和右侧的最大值即为选择 points[i][j] 时的计算结果 ans = max(ans, res) // 直接更新答案,这样下面就不直接存储 res 了,改为存储 res + j 和 res - j f[j][0] = res + j f[j][1] = res - j } } // 计算完一整行 f 后,对于每个位置 j,计算其右侧的所有 f[k] - k 的最大值 // 这可以通过倒着遍历 f 求出 sufMax[n-1] = f[n-1][1] for j := n - 2; j >= 0; j-- { sufMax[j] = max(sufMax[j+1], f[j][1]) } } return int64(ans) } func max(a, b int) int { if a > b { return a }; return b }