21 环形数组中的最大贡献值 题解 | 豆包MarsCode AI刷题

82 阅读3分钟

问题描述

小S拿到了一个长度为 n 的环形数组,并定义了两个下标i和j的贡献值公式为:

f ( i , j )=( a_i + a_j ) x dist ( i , j )

其中 dist ( i , j )是下标 i 和 j 在数组中的最短距离。小S希望找到一对下标,使得它们的贡献值尽可能大。环形数组的特点是最左和最右的元素也是相邻的。你需要帮助她找到最大贡献值。

例如,给定数组[1,2,3],由于是环形数组,任意两个下标的距离都是1,因此

f(2,3)=(2+3)x1=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

题目分析

题目要求找到环形数组中两个下标 i 和 j,使得以下公式的值最大化:

f ( i, j ) = ( a_i + a_j ) x dist ( i , j )

其中:

  • a_i 和 a_j 是数组中的两个元素。
  • dist ( i , j ) 是下 i 和 j 在环形数组中的最短距离。

环形数组的特点是最左和最右的元素是相邻的,因此计算距离时需要特别注意。数组长度为 n 时:

  • 普通距离为 | j - i | 。
  • 环形距离为 n - | j - i | 。
  • 最短距离公式为:dist ( i , j ) = min ( | j - i | , n - | j - i | ) 。

解题思路

1.暴力枚举

  • 使用两重循环,第一层固定下标 i ,第二层遍历所有 j ,计算f ( i , j ) 。
  • 时间复杂度 O(n2),适合 n 较小时使用。

2.计算最短距离

  • | j - i | :表示从 i 到 j 的顺时针距离。
  • n - | j - i | :表示从 i 到 j 的逆时针距离。
  • 使用公式: dist ( i , j ) = min ( | j - i | , n - | j - i | ) 。

3.贡献值更新

  • 每次计算 f ( i , j ) = ( a_i + a_j ) x dist ( i , j ) 后,与当前最大值比较,保留最大值。

4.边界条件 如果数组长度 n = 1,无法形成两个下标对,返回结果为0。

解题步骤

输入和初始化

1.输入数据

  • 环形数组长度 n 和数组 a。
  • 特殊情况:当 n = 1 时,直接返回0。

2.初始化最大值

  • 使用变量 max 记录最大贡献值,初始值为Integer.MIN_VALUE(确保正确更新)。

枚举所有下标对

1.外层循环:遍历下标 i 。

2.内层循环:遍历下标 j (注意 j > i 保证每对只计算一次)。

计算贡献值

1.计算最短距离

  • dist ( i , j ) = min ( | j - i | , n - | j - i | )

2.计算贡献值

  • f ( i , j ) = ( a_i + a_j ) x dist ( i , j ) 。

3.更新最大值

  • 比较 max 和当前贡献值 f ( i , j ) ,保留较大值。

输出结果

  • 返回变量 max 的值。

代码实现

public class Main {
    /**
     * 求环形数组的最大贡献值
     * @param n 数组长度
     * @param a 环形数组
     * @return 最大贡献值
     */
    public static int solution(int n, int[] a) {
        // 如果数组只有一个元素,无法形成有效的下标对
        if (a.length == 1) return 0;

        // 初始化最大贡献值
        int max = Integer.MIN_VALUE;

        // 枚举所有下标对
        for (int i = 0; i < a.length; i++) {
            for (int j = i + 1; j < a.length; j++) {
                // 计算贡献值
                int temp = (a[i] + a[j]) * calculateDistance(i, j, a.length);
                // 更新最大贡献值
                max = Math.max(max, temp);
            }
        }

        // 返回最大贡献值
        return max;
    }

    /**
     * 计算两个下标之间的最短距离
     * @param i 下标1
     * @param j 下标2
     * @param n 数组长度
     * @return 最短距离
     */
    public static int calculateDistance(int i, int j, int n) {
        int directDistance = Math.abs(j - i); // 顺时针距离
        int circularDistance = n - directDistance; // 环形距离
        return Math.min(directDistance, circularDistance); // 返回最短距离
    }

    /**
     * 主函数:测试用例
     */
    public static void main(String[] args) {
        // 测试用例 1
        System.out.println(solution(3, new int[]{1, 2, 3}) == 5); // 期望输出:5
        // 测试用例 2
        System.out.println(solution(4, new int[]{4, 1, 2, 3}) == 12); // 期望输出:12
        // 测试用例 3
        System.out.println(solution(5, new int[]{1, 5, 3, 7, 2}) == 24); // 期望输出:24
    }
}

总结

通过暴力枚举法,准确计算所有下标对的贡献值。代码逻辑清晰,适合解题需求,特别是当数组规模较小时效果较佳。