环形数组中的最大贡献值之题解
题目概述
小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 的环形数组中找到一对下标 (i, j),使它们的贡献值 f(i, j) = (a_i + a_j) × dist(i, j) 最大。其中 dist(i, j) 是下标 i 和 j 在数组中的最短距离。
考虑需要实现的功能
-
遍历所有可能的下标对:
- 使用两层循环遍历所有可能的下标对
(i, j),其中i和j不能相同。
- 使用两层循环遍历所有可能的下标对
-
计算最短距离:
- 对于每一对
(i, j),计算它们之间的最短距离dist(i, j)。
- 对于每一对
-
计算贡献值:
- 使用公式
(a_i + a_j) × dist(i, j)计算每一对(i, j)的贡献值。
- 使用公式
-
更新最大贡献值:
- 在遍历过程中,不断更新最大贡献值。
算法步骤
-
初始化一个变量
maxContribution用于存储最大贡献值,初始值为 0。 -
使用两层循环遍历所有可能的下标对
(i, j):- 如果
i不等于j,则计算dist(i, j)。 - 计算贡献值
contribution = (a_i + a_j) × dist(i, j)。 - 更新
maxContribution为max(maxContribution, contribution)。
- 如果
-
返回
maxContribution。
实现代码
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之间的最短距离
int dist = Math.min(Math.abs(i - j), n - Math.abs(i - j));
//计算贡献值f(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);
}
}
输出范例
true
true
true
具体运行步骤
-
初始化
maxContribution:- 在
solution方法中,首先初始化一个变量maxContribution,用于存储最大贡献值,初始值为 0。
- 在
-
遍历所有可能的下标对
(i, j):-
使用两层循环遍历所有可能的下标对
(i, j):- 外层循环
for (int i = 0; i < n; i++)遍历数组中的每一个元素,i从 0 到n-1。 - 内层循环
for (int j = 0; j < n; j++)遍历数组中的每一个元素,j从 0 到n-1。
- 外层循环
-
-
计算最短距离
dist(i, j):-
在内层循环中,首先检查
i是否等于j。如果i不等于j,则继续执行以下步骤:1. - - 计算下标i和j之间的最短距离dist:dist = Math.min(Math.abs(i - j), n - Math.abs(i - j))Math.abs(i - j)计算i和j之间的直接距离。n - Math.abs(i - j)计算从数组末尾绕回到数组开头的情况。Math.min取两者中的较小值,即为最短距离。
-
-
计算贡献值
f(i, j):- 使用公式
(a[i] + a[j]) * dist计算贡献值contribution。
- 使用公式
-
更新最大贡献值:
- 使用
Math.max(maxContribution, contribution)更新maxContribution,确保maxContribution始终存储当前的最大贡献值。
- 使用
-
返回最大贡献值:
- 在遍历完所有可能的下标对后,返回
maxContribution。
- 在遍历完所有可能的下标对后,返回
-
测试用例:
- 在
main方法中,调用solution方法并打印结果,验证代码的正确性。
- 在
需要注意的tips
-
环形数组的特性:
- 数组的首尾是相连的,因此计算两个下标之间的最短距离时,需要考虑两种情况:直接距离和绕回距离。
-
贡献值的计算:
f(i, j) = (a_i + a_j) × dist(i, j)dist(i, j)是通过Math.min(Math.abs(i - j), n - Math.abs(i - j))计算得到的。
-
遍历所有可能的下标对:
- 使用两层循环遍历所有可能的下标对
(i, j),其中i和j不能相同。
- 使用两层循环遍历所有可能的下标对
用到的Java方法
-
Math.min:- 用于计算两个下标之间的最短距离。
- 语法:
Math.min(a, b),返回a和b中的较小值。
-
Math.abs:- 用于计算两个下标之间的直接距离。
- 语法:
Math.abs(a),返回a的绝对值。
-
Math.max:- 用于更新最大贡献值。
- 语法:
Math.max(a, b),返回a和b中的较大值。
-
for循环:- 用于遍历数组中的所有元素。
- 语法:
for (int i = 0; i < n; i++),遍历从 0 到n-1的所有下标。