leetcode 1937. 扣分后的最大得分「动态规划」「拆项」

1937. 扣分后的最大得分

题目描述:

给你一个n*m的整数矩阵ar,一开始你的得分为0,你想最大化从矩阵中得到的分数

你的得分方式为:每一行 中选取一个格子,选中坐标为 (r, c) 的格子会给你的总得分 增加 points[r][c]

然而,相邻行之间被选中的格子如果隔得太远,你会失去一些得分。对于相邻行 rr + 1 (其中 0 <= r < m - 1),选中坐标为 (r, c1)(r + 1, c2) 的格子,你的总得分 减少 abs(c1 - c2)

请你返回你能得到的 最大 得分

思路:

很经典的拆项思路

d p i j dpij dpij表示前 i − 1 i-1 i−1行均选择了一个格子,第 i i i行选了第 j j j个格子,获得的最大价值

很显然状态要从上一行转移过来

  • d p i j = m a x ( d p i j , a r i j + d p i − 1 k − a b s ( k − j ) ) dpij = max(dpij, arij + dpi - 1k - abs(k - j)) dpij=max(dpij,arij+dpi−1k−abs(k−j))

如果这样暴力转移,则时间复杂度是 O ( n ∗ m ∗ m ) O(n*m*m) O(n∗m∗m),一定会超时的

我们考虑拆项,根据 k k k和 j j j的大小,分情况讨论

  • d p i j = m a x ( d p i j , t r i j + ( d p i − 1 k + k ) − j ) , k < = j dpij = max(dpij, trij + (dpi-1k + k) - j), k <= j dpij=max(dpij,trij+(dpi−1k+k)−j),k<=j
  • d p i j = m a x ( d p i j , t r i j + ( d p i − 1 k − k ) + j ) , k > j dpij = max(dpij, trij + (dpi-1k - k) + j), k > j dpij=max(dpij,trij+(dpi−1k−k)+j),k>j

对于 d p i j dpij dpij我们如果可以用 O ( 1 ) O(1) O(1)的时间得到 m a x { d p i − 1 k + k } , k < = j max\{dpi-1k + k\},k<=j max{dpi−1k+k},k<=j 和 m a x { d p i − 1 k − k } max\{dpi-1k-k\} max{dpi−1k−k}的值就行了

所以我们记录一个前缀最大值数组和一个后缀最大值数组,分别记录即可

同时,我们可以发现转移的时候只和上一维度的值有关,可以用滚动数组优化空间

所以最后的时间复杂度是 O ( n ∗ m ) O(n*m) O(n∗m)

cpp 复制代码
class Solution {
public:
    long long maxPoints(vector<vector<int>>& tr) {
        int n = tr.size(), m = tr[0].size();
        vector<long long>dp(m + 1);
        vector<long long>pre(m + 2), suf(m + 2);
        for(int j = 1; j <= m + 1; ++j){
            pre[j] = j;
            suf[j] = -j;
        }
        for(int i = 1; i <= n; ++i){   
            for(int j = 1; j <= m; ++j){
                dp[j] = tr[i - 1][j - 1] + max(pre[j] - j, suf[j + 1] + j);
            }
            for(int j = 1; j <= m; ++j){
                pre[j] = max(pre[j - 1], dp[j] + j);
            }
            for(int j = m; j >= 1; --j){
                suf[j] = max(suf[j + 1], dp[j] - j);
            }
        }
        long long ans = 0;
        for(int i = 1; i <= m; ++i)ans = max(ans, dp[i]);
        return ans;
    }
};
相关推荐
血小板要健康10 小时前
链表 阶段算法总结
java·数据结构·笔记·算法·leetcode·链表
a1879272183110 小时前
【算法】回溯算法(三):三记重锤与 N 皇后——记忆化、状态设计与三层漏斗
算法·leetcode·go·剪枝·回溯·n皇后·算法讲解
青 春 记 忆13 小时前
LeetCode 350. 两个数组的交集 II|Python 解法详解
python·算法·leetcode
闻缺陷则喜何志丹16 小时前
【动态规划】P3609 [USACO17JAN] Hoof, Paper, Scissor G
c++·算法·动态规划·洛谷
圣保罗的大教堂17 小时前
leetcode 3903. 最小稳定下标 I 简单
leetcode
sylviiiiiia18 小时前
Leetcode hot100 多数元素/相交链表/反转链表
算法·leetcode·链表
CoderYanger18 小时前
A.每日一题:3622. 判断整除性
java·程序人生·算法·leetcode·面试·职场和发展·蓝桥杯
rannn_11118 小时前
【力扣hot100】动态规划专题|70、118、198、279、322、139、300、152、416、32
算法·leetcode·动态规划
我不会起名字32218 小时前
一天一道算法题(26):栈的简单应用
java·数据结构·python·算法·leetcode·golang·
a1879272183119 小时前
【算法】动态规划入门:从打家劫舍到状态设计的三堂课
算法·leetcode·动态规划·dp·回溯·暴力