观光景点组合得分问题 | 豆包MarsCode KK 刷题 No.11

60 阅读2分钟

这道题可以暴力o(n²)做,但是显得比较笨拙。下面给出一个o(n)的算法。

题目描述

小R正在研究一组观光景点,每个景点都有一个评分,保存在数组 values 中,其中 values[i] 表示第 i 个观光景点的评分。同时,景点之间的距离由它们的下标差 j - i 表示。

一对景点 (i < j) 的观光组合得分为 values[i] + values[j] + i - j,也就是两者评分之和减去它们之间的距离。

小R想知道,在哪种情况下能够获得观光景点组合的最高得分。


测试样例

样例1:

输入:values = [8, 3, 5, 5, 6]
输出:11

代码

#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

int solution(std::vector<int> values) {
    int max_i = values[0] + 0; // 初始化 max_i
    int max_score = 0; // 初始化最大得分

    for (int j = 1; j < values.size(); ++j) {
        // 计算当前的得分
        int current_score = max_i + values[j] - j;
        // 更新最大得分
        max_score = max(max_score, current_score);
        // 更新 max_i
        max_i = max(max_i, values[j] + j);
    }

    return max_score;
}

int main() {
    std::cout << (solution({8, 3, 5, 5, 6}) == 11) << std::endl;
    std::cout << (solution({10, 4, 8, 7}) == 16) << std::endl;
    std::cout << (solution({1, 2, 3, 4, 5}) == 8) << std::endl;
    return 0;
}

解释

代码的目的是找到一对观光景点 (i, j),使得它们的观光组合得分最大。组合得分的计算公式是 values[i] + values[j] + i - j,即两者评分之和减去它们之间的距离。 我们可以把它理解为两个数组,如下图所示。同时这个①挺关键,这也是为什么能够将复杂度从平方转化为线性的原因。就是因为它。

image.png

对这个数组进行一个线性遍历,注意向前推进。那么这带来一个问题,即如下图。

image.png

a[j]-j和a[i]+i操作,可以理解为,将i,j的绝对距离转化为了自身的值。于是不必再考虑距离的问题。同时因为是距离对称的,所以只需考虑一个方向就行。不会存在上图的那种情形。

下面是对代码的流程的演示。(最下面) 每一次循环,同时比较max_i和score_max。类似于一组数中查找最值,挨个比较保存number_max。

image.png

最关键的问题来了,在图1中我们说了。但是它的逆命题并不一定成立。即,a[j]+j如果大于max_i,result(即socre_max)不一定和a[j]+j是有关系的。这也是为什么,代码中要再进行这样比较。这边是遍历的意义!
max_i = max(max_i, values[j] + j);
current_score = max_i + values[j] - j;
max_score = max(max_score, current_score);

image.png

最后一图是一个举例论证。

image.png