观光景点组合得分问题|个人题解

119 阅读4分钟

问题描述

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

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

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


测试样例

样例1:

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

样例2:

输入:values = [10, 4, 8, 7]
输出:16

样例3:

输入:values = [1, 2, 3, 4, 5]
输出:8

问题理解

我们需要找到一对景点 (i, j),其中 i < j,使得 values[i] + values[j] + i - j 的值最大。这个表达式可以分解为两部分:

  • values[i] + i
  • values[j] - j

数据结构选择

我们可以使用一个变量来记录当前最大的 values[i] + i,然后在遍历数组时,计算 values[j] - j 并与当前最大值相加,更新最大得分。

废话不多说,上代码(完整代码需小伙伴自己组合)


int solution(std::vector<int> values) {
    int max_score=0;
    int max_i=std::numeric_limits<int>::min();
    
    for(int i=0;i<values.size();i++){
        int current_score=max_i+values[i]-i;
        max_score=max(current_score,max_score);
        max_i=max(max_i,values[i]+i);
    }
    
    return max_score; 
}

算法步骤

  1. 初始化一个变量 max_score 用于存储最大得分,初始值为负无穷大。

  2. 初始化一个变量 max_i 用于存储当前最大的 values[i] + i,初始值为负无穷大。

  3. 遍历数组 values,对于每个元素 values[j]

    • 计算当前的得分 max_i + values[j] - j
    • 更新 max_score 如果当前得分更大。
    • 更新 max_i_plus_value 如果 values[j] + j 更大。
  4. 返回 max_score

tips:

在C++中,最小值通常可以用 std::numeric_limits<int>::min() 来表示。这个函数返回 int 类型的最小值

话说到这,貌似这个题目还可以用动态规划的方法来写,那具体是怎么样的一个写法呢?

动态规划(Dynamic Programming, DP)是一种通过将问题分解为子问题来解决复杂问题的方法。对于这个问题,我们可以使用动态规划来记录每个位置的最大得分。

动态规划思路

  1. 定义状态

    • 设 dp[j] 表示以第 j 个景点为结束点的最大得分。
  2. 状态转移方程

    • 对于每个 j,我们需要找到一个 ii < j),使得 values[i] + values[j] + i - j 最大。
    • 可以将其分解为两部分:values[i] + i 和 values[j] - j
    • 因此,dp[j] = max(dp[j-1], max(values[i] + i) + values[j] - j),其中 i < j
  3. 初始化

    • dp[0] = 0,因为以第一个景点为结束点时,没有前面的景点可以组合。
  4. 最终结果

    • 最终结果为 dp 数组中的最大值。

ok下面看看完整代码

#include <vector>
#include <iostream>
#include <limits>
#include <bits/stdc++.h>
using namespace std;

int solution(std::vector<int> values) {
    int n = values.size();
    if (n == 0) return 0;

    std::vector<int> dp(n, std::numeric_limits<int>::min());
    int max_i_plus_value = std::numeric_limits<int>::min();

    for (int j = 0; j < n; ++j) {
        if (j > 0) {
            dp[j] = max(dp[j-1], max_i_plus_value + values[j] - j);
        } else {
            dp[j] = 0; // 初始化 dp[0]
        }
        max_i_plus_value = max(max_i_plus_value, values[j] + j);
    }

    return *max_element(dp.begin(), dp.end());
}

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;
}

咳咳,这里我要唠叨一下,*max_element(dp.begin(), dp.end()) 是 C++ 标准库中的一个函数调用,用于在给定的范围内找到最大值。

详细解释

  1. max_element 函数

    • max_element 是 <algorithm> 头文件中的一个函数,用于在指定范围内找到最大值。
    • 它的返回值是一个迭代器,指向范围内最大值的元素。
  2. dp.begin() 和 dp.end()

    • dp.begin() 返回指向 dp 数组第一个元素的迭代器。
    • dp.end() 返回指向 dp 数组最后一个元素之后位置的迭代器。
  3. *max_element(dp.begin(), dp.end())

    • max_element(dp.begin(), dp.end()) 返回一个迭代器,指向 dp 数组中的最大值。
    • * 操作符用于解引用这个迭代器,获取实际的最大值。

ok,结束,虽然没干什么,但还是辛苦我了

1693984465424092.jpg