翻转增益的最大子数组和 | 豆包MarsCode AI 刷题

99 阅读4分钟

问题解析

在这个问题中,我们需要计算数组在允许一次子数组翻转操作后的最大子数组和。为了找到最优解,我们需要从两个方面入手:

  1. 不翻转子数组时的最大子数组和
  2. 翻转一次子数组后可能获得的最大子数组和

通过这两部分,我们可以找到翻转操作的潜力并计算可能的最优结果。


解题思路

1. 最大子数组和的计算
  • 计算最大子数组和是经典问题,可以用 Kadane's 算法高效解决。
  • Kadane's 算法的核心思想是用一个变量 current_sum 表示以当前元素结尾的子数组合,并通过递归公式更新: current_sum=max⁡(num,current_sum+num)
  • 同时,维护一个全局最大值 max_sum,在每一步更新: max_sum=max⁡(max_sum,current_sum)
  • 该算法的时间复杂度为 O(N),适用于较大的数组。
2. 考虑翻转操作的效果
  • 翻转子数组可能改变最大子数组和,因为翻转会让某些负数变为有利因素,同时可能消除某些区间的不利影响。

  • 我们需要遍历数组中的所有可能的子数组翻转:

    1. 固定起点 i
    2. 固定终点 j
    3. 翻转子数组 data_array[i:j+1]
    4. 拼接翻转后的完整数组,重新计算最大子数组和。
  • 遍历所有可能的子数组翻转,记录其中的最大值。

3. 整体方案
  • 第一步:用 Kadane's 算法计算不翻转时的最大子数组和 max_sum_original
  • 第二步:遍历数组的所有可能子数组,尝试翻转,重新计算最大子数组和。
  • 第三步:返回不翻转和翻转情况下的最大值。

代码实现

def solution(N, data_array): 
    # 用Kadane's算法计算最大子数组和
    def max_subarray_sum(arr):
        max_sum = float('-inf')
        current_sum = 0
        for num in arr:
            current_sum = max(num, current_sum + num)
            max_sum = max(max_sum, current_sum)
        return max_sum
        
    # 第一步,计算不进行翻转时的最大子数组和
    max_sum_original = max_subarray_sum(data_array)
        
    # 第二步,尝试翻转所有子数组
    max_sum_with_flip = max_sum_original
    for i in range(N):
        for j in range(i + 1, N):
            # 翻转子数组 data_array[i:j+1]
            flipped_array = data_array[:i] + data_array[i:j+1][::-1] + data_array[j+1:]
            # 计算翻转后的最大子数组和
            max_sum_with_flip = max(max_sum_with_flip, max_subarray_sum(flipped_array))
    
    return max_sum_with_flip

if __name__ == "__main__":
    #  You can add more test cases here
    array1 = [-85, -11, 92, 6, 49, -76, 28, -16, 3, -29, 26, 37, 86, 3, 25, -43, -36, -27, 45, 87, 91, 58, -15, 91, 5, 99, 40, 68, 54, -95, 66, 49, 74, 9, 24, -84, 12, -23, -92, -47, 5, 91, -79, 94, 61, -54, -71, -36, 31, 97, 64, -14, -16, 48, -79, -70, 54, -94, 48, 37, 47, -58, 6, 62, 19, 8, 32, 65, -81, -27, 14, -18, -34, -64, -97, -21, -76, 51, 0, -79, -22, -78, -95, -90, 4, 82, -79, -85, -64, -79, 63, 49, 21, 97, 47, 16, 61, -46, 54, 44]
    print(solution(5, [1, 2, 3, -1, 4]) == 10 )
    print(solution(100, array1) == 1348)

时间复杂度分析

  1. Kadane's 算法:每次调用最大子数组和的时间复杂度是 O(N)。
  2. 遍历所有子数组翻转:总共有 O(N2) 种子数组需要翻转,每次翻转后需重新计算最大子数组和,因此总时间复杂度为 O(N3)。

优化思路

  1. 局部计算翻转增益:翻转的子数组仅影响其内部及两侧的元素,可以直接计算翻转带来的增益,而不是构造整个数组。
  2. 动态规划优化:通过记录当前最大和及翻转状态,避免重复计算。

示例测试

  1. 输入 1[1, 2, 3, -1, 4]

    • 原始最大子数组和:[1, 2, 3, -1, 4] = 10
    • 翻转 [-1, 4]:结果仍为 10
    • 输出:10
  2. 输入 2:长数组,测试极限情况。


总结

本题是经典问题“最大子数组和”的升级版,添加了翻转操作。暴力方法可以解决小规模问题,但时间复杂度较高;优化方法需要结合局部增益分析和动态规划。