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

97 阅读3分钟

题目描述

本题是一个典型的动态规划问题,要求在一组观光景点中找到一对景点,使得观光组合得分最高。观光组合得分定义为:values[i] + values[j] + i - j,其中 values[i]values[j] 分别表示第 i 个和第 j 个景点的评分,ij 分别表示景点的下标。题目要求 i < j,即第一个景点的下标必须小于第二个景点的下标。

解题思路

为了求解这个问题,我们可以使用动态规划(Dynamic Programming,简称 DP)的方法。动态规划是一种将复杂问题分解成简单子问题求解的算法设计技术,它将子问题的解存储起来,避免重复计算,从而提高算法的效率。

我们可以定义一个一维数组 dp,其中 dp[i] 表示当选第 i 个景点作为第一个景点时,第二个景点选哪个可以使得分最高。具体步骤如下:

  1. 初始化 dp 数组,dp[n - 2] = n - 1,因为当只有一个景点可选时,只能选择最后一个景点。

  2. 从后往前遍历景点,对于每个景点 i,计算两个得分:

    • score1:选择 j = dp[i + 1] 作为第二个景点时的得分。
    • score2:选择 j = i + 1 作为第二个景点时的得分。
  3. 比较两个得分,将较大的得分对应的景点下标赋值给 dp[i]。可以这样做的原因是:如果选第i个景点作为第一个景点时,如果目标的第二个景点下标的ji + 2 <= j < n 的范围中,若要使values[i] + values[j] + i - j最大,即values[j] - j最大,则目标的j应该也能使values[i + 1] + values[j] + i + 1 - j最大,因此j就是当选择第i + 1个景点作为第一个景点时所选择的能使最终得分最高的景点,即j = dp[i + 1]。如果第二个景点的下标ji + 1 <= j < i + 2的范围中,则只能j = i + 1。因此,只要根据j = dp[i + 1]j = i + 1两种情况,计算并比较最终的得分哪个更大,将dp[i]设为对应的j即可。

  4. 遍历完成后,dp 数组中的每个元素都表示了当选第 i 个景点作为第一个景点时,第二个景点的最优选择。

  5. 再次遍历 dp 数组,计算所有可能的观光组合得分,并找出最大值。

代码实现

以下是题目给出的正确代码:

public class Main {
    public static int solution(int[] values) {
        if (values.length <= 1) {
            return 0;
        }
        int n = values.length;

        // dp[i] = j 表示:当选第i个景点作为第一个景点时,第二个景点选第j个景点可以使得分最高
        int[] dp = new int[n];
        dp[n - 2] = n - 1;
        for (int i = n - 3; i >= 0; i--) {
            int lastJ = dp[i + 1];
            int score1 = values[lastJ] + i - lastJ;
            int score2 = values[i + 1] - 1;
            if (score1 > score2) {
                dp[i] = lastJ;
            } else {
                dp[i] = i + 1;
            }
        }

        int ret = Integer.MIN_VALUE;
        for (int i = 0; i < n - 1; i++) {
            int j = dp[i];
            ret = Math.max(ret, values[i] + values[j] + i - j);
        }
        return ret;
    }

    public static void main(String[] args) {
        System.out.println(solution(new int[]{8, 3, 5, 5, 6}) == 11 ? 1 : 0);
        System.out.println(solution(new int[]{10, 4, 8, 7}) == 16 ? 1 : 0);
        System.out.println(solution(new int[]{1, 2, 3, 4, 5}) == 8 ? 1 : 0);
    }
}

时间复杂度和空间复杂度

  • 时间复杂度:O(n),其中 n 为景点数组的长度。我们需要遍历两次数组,第一次是初始化 dp 数组,第二次是计算最大得分,因此时间复杂度为 O(n)
  • 空间复杂度:O(n),我们使用了一个长度为 n 的一维数组 dp 来存储中间结果。