[M前缀和] lc1014. 最佳观光组合(思维+前缀和+算法优化)

本文介绍了LeetCode上的两道题目,分别是1014.最佳观光组合和[Mdp]lc1937.扣分后的最大得分。主要探讨如何通过动态规划优化算法,实现一次遍历解决这类问题。方法一是利用前缀最大值数组和逆序遍历,方法二是直接更新前缀最大值,两者均能在O(n)的时间复杂度和O(1)的空间复杂度内完成。
摘要由CSDN通过智能技术生成

1. 题目来源

链接:1014. 最佳观光组合

进阶题:[Mdp] lc1937. 扣分后的最大得分(dp优化+前后缀优化+周赛250_3)

2. 题目解析

思维题,算法优化,两次遍历妥妥超时,也没啥二段性可言,没想到是一次遍历啊。

方法一:

  • 简单精心转换:(A[i]+i)+(A[j]-j) 则可以通过一次顺序遍历,用一个数组 maxA[i] 来维护前 i 个位置上 A[i]+i 的最大值。然后在逆序遍历,用一个变量维护后半段 A[j]-j 的最大值,查询 maxA[j] 即可知道当前位置上 A[i]+i 的最大值,累加,每次更新答案最大值即可。
  • 由于需要保证 i<j,所以针对 j 的遍历需要逆向遍历。
  • 两次遍历即可找到答案。
  • 需要保证 i<j,故求最值的时候细节需要注意。维护后 j 个最大值,前半段最大值是 maxA[j - 1]

方法二:

  • 用一个变量维护前半段 A[i]+i 的最大值,直接和当前的 A[j]-j 累加,更新答案,并更新前半段的 A[i]+i 的最大值即可。
  • 这样一次遍历,就能找到答案。

时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( 1 ) O(1) O(1)


方法一:

class Solution {
public:
    int maxScoreSightseeingPair(vector<int>& values) {
        int n = values.size();
        vector<int> maxA(n);
        maxA[0] = values[0];
        for (int i = 1; i < n; i ++ ) maxA[i] = max(maxA[i - 1], values[i] + i);

        int res = -1e9, maxB = -1e9;
        for (int i = n - 1; i >= 1; i -- ) {
            maxB = max(maxB, values[i] - i);
            res = max(res, maxA[i - 1] + maxB);
        }

        return res;
    }
};

其实,如果循环从数组下标 1 开始的话,答案和最值都应该赋一个初始值,例如 for(int i = 0; i < n - 1; i ++ ) 这种,当只有一个元素的时候,根本进不去循环,res=-1e9 将直接返回。已经吃了很多次亏了…

class Solution {
public:
    int maxScoreSightseeingPair(vector<int>& values) {
        int n = values.size();
        vector<int> maxA(n);
        maxA[0] = values[0];
        for (int i = 1; i < n; i ++ ) maxA[i] = max(maxA[i - 1], values[i] + i);

        int maxB = values[n - 1] - (n - 1);
        int res = maxA[n - 2] + maxB;
        for (int i = n - 1; i >= 1; i -- ) {
            maxB = max(maxB, values[i] - i);
            res = max(res, maxA[i - 1] + maxB);
        }

        return res;
    }
};

方法二:最优解法了

class Solution {
public:
    int maxScoreSightseeingPair(vector<int>& values) {
        int n = values.size();
        int res = -1e9, a = -1e9;
        for (int i = 0; i < n; i ++ ) {
            res = max(res, a + values[i] - i);
            a = max(a, values[i] + i);
        }

        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值