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

56 阅读3分钟

问题描述

小S拿到了一个长度为 n 的环形数组,并定义了两个下标 i 和 j 的贡献值公式为:f(i, j) = (a_i + a_j) × dist(i, j),其中 dist(i, j) 是下标 i和 j 在数组中的最短距离。小S希望找到一对下标,使得它们的贡献值尽可能大。环形数组的特点是最左和最右的元素也是相邻的。你需要帮助她找到最大贡献值。 例如,给定数组 [1, 2, 3],由于是环形数组,任意两个下标的距离都是1,因此 f(2,3)=(2+3)×1=5


分析

观察给出的贡献值公式,不难发现,解决这个问题的关键是求出 dist(i,j) (即正确处理数组头尾下标问题)。所以此时考虑将“获取最短距离问题”拆解出来。

现在定义一个path_length函数来解决这个问题。

def path_length(m: int,c: int,d: int):
    length = 0
    if abs(c - d) <= (m / 2) :
        length = abs(c - d)
    else:
        length = m - abs(c - d)
    return length

m 是数组长度,length 是距离,cd分别是两个下标,用abs(c - d)获取两个下标之间的距离(取绝对值可以不用考虑下标先后的问题)。

我们先将距离length设为0,由于环形数组中两个元素之间有两种距离求解方式,即从一个元素向左或者向右查找另一个元素(向前或向后)。由此可知,要想求最短距离,m/2 是一个临界点,一旦从一种方向获取的距离abs(c - d)超过这个值(此时表明此路径占了数组一半以上的长度,明显不是最小值),我们可以转而取另一个方向上的距离m - abs(c - d)

我们定义path_length函数的时候,使用了m/2 为临界点,那么,如果m(数组的长度)比较小,是否会出现逻辑问题?

根据题意 “定义了两个下标 i 和 j” 应该是不存在m=0或m=1(没有元素或只有一个元素)的情况。 m=2时,不管怎么取,距离都是1,满足abs(c - d) <= (m / 2),执行的是length = abs(c - d)m=3时,取下标02的距离时,abs(2 - 0) > m/2,此时反向取距离,结果为1。(查找一个环的距离,也就是正反两个方向查找的路径刚好组成一个环,两个路径和为m,length = m - abs(c - d))

到这里,我们就解决了距离求解的问题。接下来我们考虑具体数组的求解问题。

def solution(n: int, a: list) -> int:
    max_value = 0
    for i1 in range(0, n):
        for i2 in range(0, n):
            max_value = max(max_value, (a[i1] + a[i2]) * (path_length(n, a, i2, i1)))
    return max_value

最大贡献值max_value设为0,用两个for循环进行遍历

max_value = max(max_value, (a[i1] + a[i2]) * (path_length(n, a, i2, i1)))

在遍历中更新max_value的值。注意:两个下标相等时,length = abs(c - d)的值取0,在max取较大的值时会被舍弃。因此,直接遍历就可以。

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)

测试输出结果正确。

关于数组长度问题

在不考虑m=0或1的情况下,测试正确且提交成功。由此可知,测试样例中是没有给出这两种情况的。如若考虑,只需添加条件判断语句。

if n == 1:
        具体代码
elif n == 0:
        具体代码
else:
    for i1 in range(0, n):
        for i2 in range(0, n):
            max_value = max(max_value, (a[i1] + a[i2]) * (path_length(n, a, i2, i1)))