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

73 阅读4分钟

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

问题描述

小C面对一个由整数构成的数组,他考虑通过一次操作提升数组的潜力。这个操作允许他选择数组中的任一子数组并将其翻转,目的是在翻转后的数组中找到具有最大和的子数组。小C对这个可能性很感兴趣,并希望知道翻转后的数组中可能得到的最大子数组和是多少。

例如,数组是 1, 2, 3, -1, 4。小C可以选择翻转子数组 -1, 4 得到 1, 2, 3, 4, -1 或者翻转 1, 2, 3, -1 得到 -1, 3, 2, 1, 4,在这两种情况下,最大的子数组和都是 10。

备注:子数组 是数组中的一个连续部分。

输入

  • N: 数组的长度
  • data_array: 一个长度为 N 的整数数组

输出

请你返回执行翻转操作后(也可以选择不翻转),数组中可能获得的最大子数组和。


测试样例

样例1:

输入:N = 5,data_array = [1, 2, 3, -1, 4] 输出:10

样例2:

输入:N = 4,data_array = [-3, -1, -2, 3] 输出:3

样例3:

输入:N = 3,data_array = [-1, -2, -3] 输出:-1

样例4:

输入:N = 6,data_array = [-5, -9, 6, 7, -6, 2] 输出:15

样例5:

输入:N = 7,data_array = [-8, -1, -2, -3, 4, -5, 6] 输出:10

思路:主要需要实现,求出数组中最大子数组的和,和如何翻转的问题

kadane 函数

Kadane 用于找出一个数组中最大子数组的和。Kadane 算法的基本思想是遍历数组,同时维护两个变量:max_ending_heremax_so_farmax_ending_here 表示以当前元素结尾的最大子数组和,max_so_far 表示遍历到目前为止找到的最大子数组和。

  • 初始化 max_ending_heremax_so_far 为数组的第一个元素。
  • 遍历数组的其余元素,对于每个元素,更新 max_ending_here 为当前元素和 max_ending_here 加上当前元素的最大值。这一步考虑了两种情况:当前元素单独作为一个子数组,或者将当前元素加入到前一个子数组中。
  • 更新 max_so_farmax_so_farmax_ending_here 的最大值。
  • 返回 max_so_far 作为整个数组的最大子数组和。

solution 函数

solution用于找出给定数组中,不翻转和翻转情况下的最大子数组和。

  • 首先,使用 kadane 函数计算不进行翻转时的最大子数组和,存储在 max_sum_no_flip 中。
  • 初始化 max_sum_with_flip 为负无穷大,用于存储翻转后的最大子数组和。
  • 通过两层循环遍历数组的所有可能的子数组,外层循环确定翻转的起始位置 i,内层循环确定翻转的结束位置 j
  • 对于每个可能的子数组,将其翻转并存储在 flipped_array 中。
  • 使用 kadane 函数计算 flipped_array 的最大子数组和,并更新 max_sum_with_flip
  • 最后,返回不翻转和翻转情况下的最大子数组和的最大值。

完整代码

def kadane(arr):
    # 初始化 max_ending_here 和 max_so_far 为数组的第一个元素
    max_ending_here = max_so_far = arr[0]
    # 遍历数组中除第一个元素外的其他元素
    for x in arr[1:]:
        # 更新 max_ending_here 为当前元素和 max_ending_here 加上当前元素的最大值
        max_ending_here = max(x, max_ending_here + x)
        # 更新 max_so_far 为 max_so_far 和 max_ending_here 的最大值
        max_so_far = max(max_so_far, max_ending_here)
    # 返回最大子数组和
    return max_so_far
​
def solution(N, data_array):
    # 计算不进行翻转时的最大子数组和
    max_sum_no_flip = kadane(data_array)
    # 初始化翻转后的最大子数组和为负无穷
    max_sum_with_flip = float('-inf')
    # 遍历可能的翻转起始位置 i
    for i in range(N):
        # 遍历可能的翻转结束位置 j
        for j in range(i, N):
            # 对从 i 到 j 的子数组进行翻转
            flipped_array = data_array[:i] + data_array[i:j+1][::-1] + data_array[j+1:]
            # 计算翻转后数组的最大子数组和,并更新 max_sum_with_flip
            max_sum_with_flip = max(max_sum_with_flip, kadane(flipped_array))
​
    # 返回不翻转和翻转情况下的最大子数组和的最大值
    return max(max_sum_no_flip, max_sum_with_flip)
​
if __name__ == "__main__":
    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)