青训营X豆包MarsCode 技术训练营第六课_环形数组中的最大贡献值

48 阅读4分钟

环形数组中的最大贡献值

问题描述

小S拿到了一个长度为 nn 的环形数组,并定义了两个下标 ii 和 jj 的贡献值公式为: f(i, j) = (a_i + a_j) × dist(i, j) 其中 dist(i, j) 是下标 ii 和 jj 在数组中的最短距离。小S希望找到一对下标,使得它们的贡献值尽可能大。环形数组的特点是最左和最右的元素也是相邻的。你需要帮助她找到最大贡献值。

例如,给定数组 [1, 2, 3],由于是环形数组,任意两个下标的距离都是1,因此 f(2,3)=(2+3)×1=5f(2,3)=(2+3)×1=5。


测试样例

样例1:

输入:n = 3,a = [1, 2, 3] 输出:5

样例2:

输入:n = 4,a = [4, 1, 2, 3] 输出:12

样例3:

输入:n = 5,a = [1, 5, 3, 7, 2] 输出:24

题目解析与解题思路

题目解析

给定一个长度为 n 的环形数组 a,我们需要找到两个下标 ij,使得它们的贡献值 f(i, j) 最大。贡献值的计算公式为:

f(i,j)=(ai+aj)×dist(i,j) f(i, j) = (a_i + a_j) \times \text{dist}(i, j)

其中 dist(i, j) 是下标 ij 在数组中的最短距离。由于数组是环形的,最短距离可以通过以下公式计算:

dist(i,j)=min(ij,nij)\text{dist}(i, j) = \min(\lvert i - j \rvert, n - \lvert i - j \rvert)

解题思路

1. 理解环形数组的特性

环形数组的关键在于理解其边界条件。数组的第一个元素和最后一个元素是相邻的,这意味着在计算距离时,我们需要考虑两种情况:

  • 直接计算两个下标之间的距离。
  • 通过数组的环形特性计算距离。

例如,对于数组 [1, 2, 3],下标 02 之间的距离可以是 2 - 0 = 2,也可以是 3 - 2 + 0 = 1(环形距离)。

2. 暴力解法

最直接的解法是使用暴力枚举。我们可以遍历所有可能的下标对 (i, j),计算它们的贡献值,并记录最大值。具体步骤如下:

  • 初始化一个变量 maxContribution 用于存储最大贡献值。
  • 使用两层循环遍历所有下标对 (i, j),其中 ij 不能相同。
  • 计算 dist(i, j) 并根据公式计算贡献值。
  • 更新 maxContribution

这种方法的时间复杂度为 O(n^2),对于较大的 n 可能会导致性能问题。

3. 优化思路

为了优化算法,我们可以考虑以下几点:

  • 预处理数组:可以预先计算每个元素与其他元素的距离,减少重复计算。
  • 利用对称性:由于 f(i, j) = f(j, i),我们可以减少一半的计算量。
  • 动态规划:通过动态规划的思想,记录中间结果,减少重复计算。
4. 代码实现

以下是基于暴力解法的Java代码实现:

public class Main {
    public static int solution(int n, int[] a) {
        int maxContribution = 0; // 初始化最大贡献值
        // 遍历所有可能的下标对 (i, j)
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i != j) { // 确保 i 和 j 不是同一个下标
                    // 计算 i 和 j 之间的最短距离(环形数组)
                    int dist = Math.min(Math.abs(i - j), n - Math.abs(i - j));
                    // 计算贡献值
                    int contribution = (a[i] + a[j]) * dist;
                    // 更新最大贡献值
                    maxContribution = Math.max(maxContribution, contribution);
                }
            }
        }
        return maxContribution; // 返回最大贡献值
    }

    public static void main(String[] args) {
        System.out.println(solution(3, new int[]{1, 2, 3}) == 5);
        System.out.println(solution(4, new int[]{4, 1, 2, 3}) == 12);
        System.out.println(solution(5, new int[]{1, 5, 3, 7, 2}) == 24);
    }
}
5. 进一步优化

虽然暴力解法可以解决问题,但在实际应用中,我们可能需要考虑更高效的算法。例如,可以使用动态规划来减少重复计算,或者通过预处理数组来加速距离的计算。

总结

环形数组问题是一个经典的算法问题,通过理解数组的环形特性,我们可以设计出有效的算法来解决这类问题。暴力解法虽然简单,但在处理大规模数据时可能会遇到性能瓶颈。通过优化算法,我们可以提高程序的效率,使其能够处理更大规模的数据。

在实际编程中,我们还需要考虑边界条件和异常情况,确保代码的健壮性。通过不断练习和优化,我们可以更好地掌握这类问题的解决方法,提升自己的编程能力。