You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何寻找和最大的不重叠子数组对?

寻找和最大的不重叠子数组对的高效算法

确实存在时间复杂度为O(n)的高效算法来解决这个问题,核心思路是通过预处理左右两侧的最大子数组信息,再遍历所有可能的分割点找到最优解。

算法思路

  • 预处理左侧最大子数组信息:从左到右遍历数组,维护一个数组left_info,其中left_info[i]存储从数组起始到第i个位置范围内的最大子数组的(和,起始索引,结束索引)。
  • 预处理右侧最大子数组信息:从右到左遍历数组,维护一个数组right_info,其中right_info[i]存储从第i个位置到数组结尾范围内的最大子数组的(和,起始索引,结束索引)。
  • 遍历分割点找最优解:遍历每个可能的分割位置k(将数组分为左半部分[0..k]和右半部分[k+1..n-1]),计算left_info[k].sum + right_info[k+1].sum,记录所有分割点中的最大值,以及对应的两个子数组的位置。

代码实现

基于你提供的卡丹算法,我们封装辅助函数并完成预处理与计算:

import numpy as np

def kadane_range(arr, start, end):
    """返回arr[start..end]范围内的最大子数组(和,起始索引,结束索引)"""
    subarray_sum = 0
    max_subarray_sum = np.int32(-2**31)
    finish = -1
    local_start = start

    for i in range(start, end + 1):
        subarray_sum += arr[i]
        if subarray_sum < 0:
            subarray_sum = 0
            local_start = i + 1
        elif subarray_sum > max_subarray_sum:
            max_subarray_sum = subarray_sum
            current_start = local_start
            finish = i

    if finish != -1:
        return (max_subarray_sum, current_start, finish)

    # 处理区间内全为负数的情况
    max_subarray_sum = arr[start]
    current_start = current_end = start
    for i in range(start + 1, end + 1):
        if arr[i] > max_subarray_sum:
            max_subarray_sum = arr[i]
            current_start = current_end = i
    return (max_subarray_sum, current_start, current_end)

def max_two_non_overlapping_subarrays(arr):
    n = len(arr)
    if n < 2:
        return None  # 数组长度不足,无法选取两个子数组

    # 预处理左侧信息:left_info[i]是arr[0..i]的最大子数组信息
    left_info = [None] * n
    left_info[0] = (arr[0], 0, 0)
    current_max_sum, _, _ = left_info[0]
    current_start, current_end = 0, 0
    for i in range(1, n):
        temp_sum = current_max_sum + arr[i]
        new_sum = arr[i]
        if temp_sum > new_sum and temp_sum > left_info[i-1][0]:
            current_max_sum = temp_sum
            current_end = i
            left_info[i] = (current_max_sum, current_start, current_end)
        elif new_sum > left_info[i-1][0]:
            current_max_sum = new_sum
            current_start = current_end = i
            left_info[i] = (current_max_sum, current_start, current_end)
        else:
            left_info[i] = left_info[i-1]

    # 预处理右侧信息:right_info[i]是arr[i..n-1]的最大子数组信息
    right_info = [None] * n
    right_info[-1] = (arr[-1], n-1, n-1)
    current_max_sum, _, _ = right_info[-1]
    current_start, current_end = n-1, n-1
    for i in range(n-2, -1, -1):
        temp_sum = current_max_sum + arr[i]
        new_sum = arr[i]
        if temp_sum > new_sum and temp_sum > right_info[i+1][0]:
            current_max_sum = temp_sum
            current_start = i
            right_info[i] = (current_max_sum, current_start, current_end)
        elif new_sum > right_info[i+1][0]:
            current_max_sum = new_sum
            current_start = current_end = i
            right_info[i] = (current_max_sum, current_start, current_end)
        else:
            right_info[i] = right_info[i+1]

    # 遍历所有分割点找最大值
    max_total = np.int32(-2**31)
    best_pair = None
    for k in range(n-1):
        left_sum, left_s, left_e = left_info[k]
        right_sum, right_s, right_e = right_info[k+1]
        total = left_sum + right_sum
        if total > max_total:
            max_total = total
            best_pair = ((left_sum, left_s, left_e), (right_sum, right_s, right_e))

    # 处理所有元素都是负数的情况(选两个最大的单个元素)
    if max_total < arr[0] + arr[1]:
        first_max = second_max = np.int32(-2**31)
        first_idx = second_idx = 0
        for i in range(n):
            if arr[i] > first_max:
                second_max = first_max
                second_idx = first_idx
                first_max = arr[i]
                first_idx = i
            elif arr[i] > second_max:
                second_max = arr[i]
                second_idx = i
        best_pair = ((first_max, first_idx, first_idx), (second_max, second_idx, second_idx))
        max_total = first_max + second_max

    return max_total, best_pair

# 测试示例输入
arr = [3, 3, 3, -8, 3, 3, 3]
total, pair = max_two_non_overlapping_subarrays(arr)
print(f"最大和为: {total}")
print(f"第一个子数组: 和={pair[0][0]}, 索引范围[{pair[0][1]}, {pair[0][2]}], 元素={arr[pair[0][1]:pair[0][2]+1]}")
print(f"第二个子数组: 和={pair[1][0]}, 索引范围[{pair[1][1]}, {pair[1][2]}], 元素={arr[pair[1][1]:pair[1][2]+1]}")

算法说明

  • 时间复杂度:O(n),三次线性遍历(左侧预处理、右侧预处理、分割点遍历),每个步骤均为O(n)级别。
  • 空间复杂度:O(n),用于存储左右两侧的子数组信息;若仅需计算最大和无需记录子数组位置,可优化变量将空间复杂度降至O(1)。

对于你提供的示例输入,运行代码后会得到和为18的两个子数组[3,3,3](索引0-2)和[3,3,3](索引4-6),符合预期。

内容的提问来源于stack exchange,提问作者Simd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 13:05:16