题解——11. 观光景点组合得分问题 | 豆包MarsCode AI刷题

42 阅读2分钟

原题截图

image.png

题意分析

原题题意分析

本题的题意较为简单,即有一个数组valuesvalues,对于所有的1i,jn,i<j1\le i,j\le n,i<j,找出valuesi+valuesj+ijvalues_i+values_j+i-j的最大值。

题意修改

按照原题的题意,因为i<ji<j且题目没有规定如果找不到任何一对景点输出什么值,所以本题不应出现数组大小为11的情况。但经过实测,本题的测试数据中含有数组大小为11的数据(如下图)。

image.png

所以原题的题意和测试数据出现矛盾,在不改变测试数据的前提下,必须修改题意才能使题目逻辑正确。一种可行的修改方案为,规定找不到任何一对景点时输出00,按照此方案修改后的题意如下:

有一个数组valuesvalues,对于所有的1i,jn,i<j1\le i,j\le n,i<j,输出valuesi+valuesj+ijvalues_i+values_j+i-j的最大值;如果没有任何一对i,ji,j满足1i,jn,i<j1\le i,j\le n,i<j,输出00

解题思路

本题容易想到复杂度为O(n2)O(n^2)的解法,即用两层循环暴力遍历每一对i,ji,j的组合,并计算valuesi+valuesj+ijvalues_i+values_j+i-j的值。但稍微多加思考,即可发现本题也可用时间复杂度更低的O(n)O(n)的算法来解决,即遍历时记录valuesi+ivalues_i+i的最大值,然后在后续遍历中将遍历到的数视为jj,得出valuesjjvalues_j-j的值,然后直接使用已经记录的valuesi+ivalues_i+i的最大值,得出valuesi+valuesj+ijvalues_i+values_j+i-j的最大值,即可节省一层循环,这种解法实际上使用了类似动态规划的记忆化思想。

具体解法为,如果values的大小为1,直接返回0。否则,定义变量ansmax记录答案valuesi+valuesj+ijvalues_i+values_j+i-j的最大值,变量imax记录valuesiivalues_i-i的最大值。然后将这两个变量的初值设为一个已知必定会在后续遍历中取到的值(在本题中即为某一对或某一个景点的相应值),具体来说,将ansmax的初值设为values[0] + values[1] - 1(即当i=0,j=1i=0,j=1valuesi+valuesj+ijvalues_i+values_j+i-j的值),imax的初值设为values[0](即当i=0i=0valuesiivalues_i-i的值)。从第2个数开始遍历数组,设遍历到的值为i,对于每一个i,首先更新ansmax = max(ansmax, values[i]-i+imax);,然后更新imax = max(imax, values[i]+i);(这种更新顺序保证了更新ansmax的值时,imax的值一定不会包括i本身,从而保证了i<ji<j)。遍历完成后,ansmax的值即为答案。

代码实现

#include <bits/stdc++.h>
using namespace std;
int solution(std::vector<int> values)
{
    if(values.size() == 1) return 0;
    int imax=values[0], ansmax=values[0]+values[1]-1;
    int n=values.size();
    for(int i=1;i<n;i++)
    {
        ansmax = max(ansmax, values[i]-i+imax);
        imax = max(imax, values[i]+i);
    }
    return ansmax;
}

总结

本题使用类似动态规划的记忆化方法解决,设数组valuesvalues的长度为ii,本题的时间复杂度为O(n)O(n),空间复杂度为O(1)O(1),如果你有复杂度更优的解法,欢迎在下方评论。