环形数组最大贡献值问题 | 豆包MarsCode AI刷题

85 阅读3分钟

问题分析

小S有一个长度为 n 的环形数组,环形数组的特点是首尾元素相邻。她希望找到一对下标 i,j,使得以下公式计算出的贡献值最大:

f(i,j)=(a[i]+a[j])×dist(i,j)

其中:

  • dist(i,j) 表示 i 和 j 在环形数组中的最短距离

环形数组特性

  1. 环形关系:首尾元素相邻。例如数组 [1,2,3],首尾距离为 1。

  2. 最短距离:从 i 到 j 的距离可能有两种:

    • 顺时针:直接从 i 走到 j。
    • 逆时针:从 i 绕过数组尾部到 j。
      两种距离中取较小值即为 dist(i,j)。

目标:找到 i,j 的组合,使得贡献值最大。

解题思路

公式理解

公式 f(i,j)=(a[i]+a[j])×dist(i,j) 中:

  1. 贡献值的决定因素

    • a[i]+a[j]:数值和越大,贡献值越大。
    • dist(i,j):距离越远,权重越大,但距离不能超过数组总长度的一半。
  2. 最短距离计算公式

dist(i,j)=min((j−i)%n,(i+n−j)%n)

  • 顺时针:(j−i)%n
  • 逆时针:(i+n−j)%n
  • 两者取最小值。

暴力解法

  1. 遍历所有 i,j 组合。
  2. 对于每对 i,j,计算 f(i,j) 并更新最大值。
  3. 时间复杂度为 O(n2),适合 n 较小的情况。

优化思路

  1. 减少重复计算

    • f(i,j)=f(j,i),只需计算 i<j 的情况,避免重复计算。
  2. 快速距离计算

    • 利用数组环形结构,提前计算最短距离,减少冗余运算。

代码实现

优化后的代码

	def solution(n: int, a: list) -> int:
	    max_contribution = 0
	    # 遍历 i < j 的组合
	    for i in range(n):
	        for j in range(i + 1, n):  # 确保 j > i,避免重复计算
	            # 计算最短距离
	            dist = min((j - i) % n, (i + n - j) % n)
	            # 计算贡献值
	            contribution = (a[i] + a[j]) * dist
	            # 更新最大贡献值
	            max_contribution = max(max_contribution, contribution)	  
	    return max_contribution

测试样例

if __name__ == '__main__':
    assert solution(3, [1, 2, 3]) == 5  # 最大贡献值来自 (1, 3) 的组合
    assert solution(4, [4, 1, 2, 3]) == 12  # 最大贡献值来自 (4, 3) 的组合
    assert solution(5, [1, 5, 3, 7, 2]) == 24  # 最大贡献值来自 (5, 7) 的组合

代码详解

  1. 遍历优化

    • 只遍历 i<j 的组合,避免对称计算 f(i,j)=f(j,i)。
    • 第二层循环从 j=i+1 开始。
  2. 最短距离计算

    • 顺时针:直接从 i 到 j,公式为 (j−i)%n。
    • 逆时针:从 i 经过数组尾部到 j,公式为 (i+n−j)%n。
    • 两者取最小值:dist = min((j - i) % n, (i + n - j) % n)
  3. 贡献值更新

    • 每次计算 f(i,j) 后,与当前的最大贡献值对比,更新最大值。

复杂度分析

  • 时间复杂度:优化后,内层循环减少一半,复杂度降为 O(n2/2),即 O(n2),适合中等规模数据。
  • 空间复杂度:除了存储常量变量 max_contribution,无需额外空间,复杂度为 O(1)。