青训营X豆包MarsCode 技术训练营第五篇 | 豆包MarsCode AI 刷题

53 阅读3分钟

学习笔记:环形数组中的最大贡献值


题目解析

1. 问题描述

小S需要找到环形数组中的一对下标 (i,j)(i, j),使得贡献值公式:

f(i,j)=(ai+aj)×dist(i,j)f(i, j) = (a_i + a_j) \times \text{dist}(i, j)

的值尽可能大,其中 dist(i,j)\text{dist}(i, j) 表示两个下标之间的最短距离(注意环形数组的特性)。


分析

2. 思路
  1. 计算最短距离 dist(i,j)\text{dist}(i, j)

    • 两个下标之间的距离有两种情况:

      1. ∣i−j∣|i - j|,即普通数组的距离。
      2. n−∣i−j∣n - |i - j|,即通过环形另一侧的距离。
    • 取两者的较小值:dist(i,j)=min⁡(∣i−j∣,n−∣i−j∣)\text{dist}(i, j) = \min(|i - j|, n - |i - j|)。

  2. 暴力求解

    • 枚举所有可能的下标对 (i,j)(i, j),计算贡献值。
    • 复杂度为 O(n2)O(n^2),适用于小规模数据。
  3. 优化方向(未实现)

    • 对称性利用:环形数组可以映射到线性数组中,避免重复计算。
    • 滑动窗口:在某些条件下,可以通过固定窗口快速计算一组下标的贡献值。
3. 示例分析

示例1:n=3, a=[1, 2, 3]

  • 数组长度为 3,环形特性使得任意两下标的距离均为 1。

  • 贡献值计算:

    • f(0,1)=(1+2)×1=3f(0, 1) = (1 + 2) \times 1 = 3
    • f(0,2)=(1+3)×1=4f(0, 2) = (1 + 3) \times 1 = 4
    • f(1,2)=(2+3)×1=5f(1, 2) = (2 + 3) \times 1 = 5
  • 最大贡献值:5。


代码实现

def solution(n: int, a: list) -> int:
    # 当数组长度为1时,无法形成下标对
    if n == 1:
        return 0
​
    max_contribution = float('-inf')  # 初始化最大贡献值为负无穷
​
    # 暴力枚举所有下标对
    for i in range(n):
        for j in range(i + 1, n):  # 只需计算一次 (i, j) 和 (j, i)
            # 计算最短距离
            dist = min(abs(i - j), n - abs(i - j))
            # 计算贡献值
            contribution = (a[i] + a[j]) * dist
            # 更新最大贡献值
            max_contribution = max(max_contribution, contribution)
​
    return max_contribution
​
# 测试用例
if __name__ == '__main__':
    print(solution(n=3, a=[1, 2, 3]) == 5)
    print(solution(n=4, a=[4, 1, 2, 3]) == 12)
    print(solution(n=5, a=[1, 5, 3, 7, 2]) == 24)

复杂度分析

  1. 时间复杂度

    • 外层循环遍历所有元素 ii,内层遍历 i+1i+1 到 n−1n-1,总计 O(n2)O(n^2)。
    • 时间复杂度为 O(n2)O(n^2)
  2. 空间复杂度

    • 仅使用常数级别的额外空间,复杂度为 O(1)O(1)

知识总结

1. 环形数组的特点
  • 环形数组是一种特殊数据结构,其中首尾元素相连。
  • 下标之间的距离有两种路径,需要根据实际情况计算最短路径: dist(i,j)=min⁡(∣i−j∣,n−∣i−j∣)\text{dist}(i, j) = \min(|i - j|, n - |i - j|)
2. 枚举法
  • 枚举法适合求解下标对关系问题,如本题中的最大贡献值。
  • 时间复杂度较高,但实现简单,适用于小规模数据。
3. 动态优化
  • 对于大规模数据,可以通过动态规划或滑动窗口优化计算。
  • 优化的核心是减少不必要的重复计算,例如利用对称性或累计和。

学习建议

  1. 打好基础:对于初学者,建议熟练掌握枚举法解决问题,理解暴力法的实现逻辑和适用场景。
  2. 尝试优化:了解优化方向,如利用对称性、滑动窗口等方法,逐步提高效率。
  3. 多练习环形问题:环形数组问题常见于各种题型(如环形子数组、环形最大值),需要熟悉其特性和解法。