问题描述
小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
要解决这个问题,我们需要找到环形数组中的一对下标 (i) 和 (j),使得它们的贡献值 (f(i, j) = (a_i + a_j) * {dist}(i, j)) 最大。其中,{dist}(i, j) 是下标 i 和 j 在数组中的最短距离。
思路
- 计算最短距离:
-
- 对于环形数组,下标 (i) 和 (j) 之间的最短距离可以通过以下方式计算:
{dist}(i, j) = min(|i - j|, n - |i - j|)
- 这是因为环形数组中,最短距离要么是直接的距离,要么是绕过数组另一端的距离。
2. 枚举所有可能的下标对:
-
- 我们需要枚举所有可能的下标对 ((i, j)),并计算它们的贡献值。
- 由于数组是环形的,我们需要考虑所有可能的下标对,包括跨越数组两端的情况。
- 优化计算:
-
- 直接枚举所有可能的下标对的时间复杂度是 (O(n^2)),对于较大的 (n) 可能会超时。
- 我们可以考虑使用前缀和和后缀和来优化计算,但在这个问题中,直接枚举所有可能的下标对已经足够高效。
代码实现
def max_contribution(n, a):
max_contrib = 0
for i in range(n):
for j in range(n):
if i != j:
dist = min(abs(i - j), n - abs(i - j))
contrib = (a[i] + a[j]) * dist
max_contrib = max(max_contrib, contrib)
return max_contrib
# 测试样例
print(max_contribution(3, [1, 2, 3])) # 输出:5
print(max_contribution(4, [4, 1, 2, 3])) # 输出:12
print(max_contribution(5, [1, 5, 3, 7, 2])) # 输出:24
解释
- 计算最短距离:
-
dist = min(abs(i - j), n - abs(i - j))计算下标 (i) 和 (j) 之间的最短距离。
- 计算贡献值:
-
contrib = (a[i] + a[j]) * dist计算下标 (i) 和 (j) 的贡献值。
- 更新最大贡献值:
-
max_contrib = max(max_contrib, contrib)更新最大贡献值。
- 返回结果:
-
- 最后返回最大贡献值
max_contrib。
- 最后返回最大贡献值
时间复杂度
- 直接枚举所有可能的下标对的时间复杂度是 (O(n^2))。
- 对于较小的 (n),这个复杂度是可以接受的。如果 (n) 较大,可以考虑进一步优化,例如使用滑动窗口或动态规划等方法。但对于大多数实际应用场景,直接枚举已经足够高效。