问题描述
小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
}
}
总结
通过暴力枚举法,准确计算所有下标对的贡献值。代码逻辑清晰,适合解题需求,特别是当数组规模较小时效果较佳。