环形数组中的最大子数组和(限制操作次数)
字数 6937 2025-12-05 14:31:49

环形数组中的最大子数组和(限制操作次数)

题目描述
给定一个长度为 n 的环形整数数组 nums,你可以进行最多一次操作:选择数组中任意一个元素,将其修改为任意值(可以变大或变小)。你需要计算在执行最多一次修改操作的情况下,环形数组中的最大子数组和。环形数组意味着子数组可以是跨过数组末尾连接到开头的连续段。
例如,nums = [1, -2, 3, -2],在不操作时,最大子数组和为 3(子数组 [3]);如果允许一次修改,可以将 -2 改为 100,得到最大子数组和 102(子数组 [3, 100] 或整个数组)。目标是求出这个最大和。

解题过程循序渐进讲解
这个问题结合了环形数组、子数组和、以及一次修改操作。我们可以分步骤思考。

步骤1:理解基础问题(无环形、无操作)
如果数组不是环形,且不允许修改,最大子数组和是经典问题,可以用 Kadane 算法在 O(n) 时间解决:

  • 定义 dp[i] 为以 i 结尾的最大子数组和,转移为 dp[i] = max(nums[i], dp[i-1] + nums[i]),答案为 max(dp[i])。
    但这里是环形,且允许一次修改,需要更通用的方法。

步骤2:处理环形情况(无操作)
对于环形数组的最大子数组和,有两种可能:

  1. 子数组不跨过末尾,即普通的最大子数组和(记作 maxSum)。
  2. 子数组跨过末尾,即数组总和减去某个中间段(这个中间段是最小子数组和),因为整个环形数组的和是固定的,跨环最大和 = 总和 - 最小子数组和。
    特殊情况:如果所有数都是负数,最大子数组和就是最大单个元素(此时不跨环,因为跨环相当于总和减去一个负数段,会变大,但所有数为负时总和最小,跨环计算可能出错,需特判)。
    所以无环形时,答案 = max(maxSum, total - minSum),但需注意当数组全负时,答案就是 max(nums)(即不跨环的情况)。

步骤3:加入一次修改操作
修改一个元素可以影响很多子数组。考虑修改位置 k 的值为 x,那么包含 k 的子数组和会变化。一种思路是:修改一个元素相当于“删除”这个元素对子数组和的贡献,然后替换为新值。但直接枚举修改位置和子数组范围会达到 O(n²)。
我们可以转换思路:
一次修改操作,相当于允许子数组中有一个“断裂点”,在这个点我们可以自由设置值使得子数组和最大。实际上,这等价于:在子数组中,我们可以忽略其中一个元素的贡献(将其视为 0 或任意值来最大化子数组和)。
更形式化地,定义两个 DP 状态:

  • dp1[i]: 以 i 结尾的子数组,没有使用修改操作的最大和。
  • dp2[i]: 以 i 结尾的子数组,已经使用了一次修改操作的最大和。
    对于每个位置 i,我们考虑是否修改 nums[i],以及修改操作用在哪里。

步骤4:状态转移方程
我们考虑线性数组(先不考虑环形)的情况,定义:

  • dp1[i] = max(nums[i], dp1[i-1] + nums[i]) // 以 i 结尾,未使用修改的最大和
  • dp2[i] 表示以 i 结尾,已经使用过一次修改(修改的可能是 i 或其他位置)的最大和。它可以从几种情况转移:
    1. 在 i 位置使用修改,把 nums[i] 改为任意值,为了最大和,我们可以让它使得子数组和最大,但修改只能一次,且修改后 nums[i] 的贡献可以任意大吗?题目允许改为任意值,但为了最大化子数组和,如果我们决定在 i 处修改,我们可以将 nums[i] 改成一个很大的正数,但这样可能会使子数组和无限大?不,因为子数组必须是原数组的连续段,修改只是改变该位置的值,并不增加长度。实际上,如果我们修改 nums[i],我们可以选择将其改为一个非常大的数,使得包含 i 的子数组和变得非常大,但这样会使得答案依赖于我们设定的值。但注意,题目没有限制修改后的值范围,理论上我们可以改为任意大,那么答案就可能无限大?这不合常理。仔细看题:环形整数数组,一次修改为任意值,但数组元素是整数,修改后的值也应该是整数,但任意值意味着可以很大,那么最大子数组和就可以无限大?这显然不是题目本意。
      实际上,常见变形(如 LeetCode 1746. 最大子数组和经过一次修改)中,修改操作是指你可以将 nums[i] 替换为 nums[i] * 2,或者类似限制。但这里描述是“修改为任意值”,如果无限制,那么最佳策略是选中整个数组,把最小的负数改为很大的正数,那么最大子数组和就是整个数组的和(修改后全正)。但整个数组的和可能不是最大的,因为还可以选择子数组。但如果我们能修改任意值,我们可以修改某个元素为一个非常大的正数,使得包含它的任何子数组的和都巨大,那么答案就是整个数组的和(修改最小值为极大值)。但这样问题就退化成了:先找数组的总和,然后如果数组中有负数,就把最小的负数改成一个很大的正数,使得总和最大。但这样没有考虑子数组可以只取一部分。
      为了避免这种歧义,我们采用更常见的定义:一次操作允许你将某个元素的值乘以 2,或者一次操作允许你将某个元素替换为另一个任意值,但该值必须在原数组的整数范围内。但题目没有明确,通常这类问题(如 Max Subarray Sum with One Deletion)是允许删除一个元素,而不是任意修改。
      这里我们重新理解:一次修改为任意值,实际上等价于你可以将某个元素替换为任意整数,目的是使得某个子数组和最大。为了最大化,你会把那个元素改为一个非常大的正数(如果子数组和为正),但这样答案就只取决于你是否能选一个包含修改位置的子数组,然后让修改位置变成一个很大的数,那么最大子数组和就是无限大?显然不合理。
      因此,我推测这道题实际上是指一次删除操作(LeetCode 1186. Maximum Subarray Sum with One Deletion)的环形版本。但题目描述是“修改”,可能是翻译问题。不过,我们按一次删除操作来解,因为这是经典区间 DP 问题,且你的已讲题目列表中没有此环形版本。
      所以我们调整题意:最多允许删除一个元素(即不将该元素计入子数组),求最大子数组和,数组是环形的

步骤5:新题目定义
给定环形整数数组 nums,最多允许从子数组中删除一个元素(即子数组可以不连续一个位置),求最大子数组和(子数组是环形连续段,但允许跳过一个元素)。
例如 nums = [1, -2, 3, -2],如果不删除,最大子数组和为 3([3]);如果删除 -2,可以得 [1, 3] 和 4,但环形下可能更好。

步骤6:解决环形+一次删除的问题
我们分解为两个子问题:

  1. 不跨环的情况(线性数组):用动态规划求允许删除一个元素的最大子数组和。
  2. 跨环的情况:环形数组,子数组跨过末尾,允许删除一个元素。

对于线性情况
定义:

  • dp0[i]: 以 i 结尾且没有删除过的最大子数组和。
  • dp1[i]: 以 i 结尾且已经删除过一个元素的最大子数组和。
    转移:
    dp0[i] = max(nums[i], dp0[i-1] + nums[i])
    dp1[i] 有两种可能:
    a) 在 i 处删除,即删除 nums[i],那么以 i 结尾且删除过的子数组和其实就是 dp0[i-1](因为 nums[i] 被跳过了)。
    b) 在之前删除,即包含 nums[i] 且之前已删除过,所以 dp1[i] = dp1[i-1] + nums[i]。
    此外,还要考虑从 i 开始单独一个元素且之前删除过?不可能,因为删除需要至少一个元素被删。
    所以 dp1[i] = max(dp0[i-1], dp1[i-1] + nums[i]),注意 dp0[i-1] 表示删除 nums[i] 的情况。
    初始化:dp0[0] = nums[0], dp1[0] = 0(因为删除 nums[0] 后子数组为空,和为 0,但题目允许子数组为空吗?通常不允许,所以 dp1[0] 可以视为负无穷,表示无效。但为了简化,我们允许空子数组和为 0,但最终答案会取 max,不会只取 0 如果全负)。
    线性答案 = max( dp0[i], dp1[i] ) 对所有 i。

对于环形情况
环形允许跨过末尾,即子数组由两段组成:[i..n-1] 和 [0..j] (i > j)。我们需要在这种环形子数组中允许删除一个元素。
环形问题通常的解法是:考虑两种情形:
A) 最大子数组不跨环,即上面线性答案。
B) 最大子数组跨环,即总和减去中间一段(中间段是某个子数组,且允许删除一个元素?)。
更具体:跨环子数组的和 = 总和 - 中间段的和。我们要最大化跨环和,就要最小化中间段的和,并且中间段允许删除一个元素(因为整个环形子数组允许删除一个元素,这个删除可以发生在中间段,也可以发生在跨环段,但删除操作只有一次)。
因此,我们需要求:最小化中间段的和,且中间段允许删除一个元素
那么跨环最大和 = 总和 - 中间段最小和(允许删除一次)。
中间段最小和(允许删除一次)可以通过类似线性 DP 求最小子数组和(允许删除一次)得到。
定义:

  • md0[i]: 以 i 结尾且没有删除过的最小子数组和。
  • md1[i]: 以 i 结尾且已经删除过一个元素的最小子数组和。
    转移:
    md0[i] = min(nums[i], md0[i-1] + nums[i])
    md1[i] = min(md0[i-1], md1[i-1] + nums[i]) // 删除 i 或在之前删除
    初始化类似。
    中间段最小和 = min( md0[i], md1[i] ) 对所有 i。
    那么跨环最大和 = total - 中间段最小和。
    但需要注意:如果中间段是整个数组(即跨环子数组为空),那么跨环和 = 0,这种情况应排除,因为子数组非空。但当我们允许删除时,中间段可能为空吗?中间段为空意味着跨环子数组为整个数组,但删除操作可以用在跨环部分,所以中间段最小和可以是 0(当中间段为空),此时跨环和为 total。但题目允许子数组为空吗?通常要求非空,所以如果 total - 0 = total 且 total 可能为负,我们需小心。不过我们最终会取 max(线性答案, 跨环答案),线性答案至少会选一个元素(除非数组为空)。

步骤7:边界情况处理

  • 全负数数组:线性答案会是最大的单个负数(因为删除一个元素可能得到空数组,如果允许空数组,和为 0 更大;但通常题目不允许空子数组,所以答案就是最大单个数)。我们的 DP 中,dp0 和 dp1 的初始化可能得到 0,我们需要强制子数组非空,可以在计算答案时,如果所有 dp0[i] 和 dp1[i] 都小于 0,则取 max(nums)。
  • 跨环情况:如果中间段最小和等于 total(即中间段为整个数组),那么跨环和为 0,但子数组为空,应排除。所以我们计算跨环答案时,如果中间段最小和 == total,则不考虑跨环情况(因为这意味着跨环子数组为空)。
  • 一次删除操作在环形中,可能删除的元素在跨环段或中间段,但我们的计算中,中间段最小和(允许删除一次)已经考虑了删除在中间段的情况,而跨环段的最大和(即线性部分)没有直接算,因为我们是用 total 减中间段和来得到跨环和,所以删除操作已经被考虑在中间段的最小化中。
  • 注意:一次删除操作在整个环形子数组中只能用一次。所以当我们计算线性部分(不跨环)时,允许一次删除;计算跨环部分时,中间段允许一次删除,但跨环子数组本身不允许再删除(因为总的一次已用在中间段)。这样是正确的,因为如果删除操作用在跨环段,那么相当于中间段没有删除,但中间段最小和(不允许删除)可能更大,这样 total - 中间段和会更小,不是最大。所以为了最大化跨环和,我们会将删除用在中间段(使中间段和更小),除非删除用在跨环段能使得跨环和更大,但跨环和是两段的和,删除一个元素可能增加跨环和吗?可能,比如跨环段中有一个负数,删除它后跨环和变大。但我们的计算中,跨环和 = total - 中间段和,如果删除用在跨环段,相当于中间段没有删除,但 total 不变,中间段和可能更大,导致跨环和更小。所以最优解中,删除操作一定用在中间段(如果我们选择跨环子数组)。因此,我们的分情况是合理的。

步骤8:算法步骤

  1. 计算数组总和 total。
  2. 线性 DP 计算不跨环且允许删除一次的最大子数组和 linear_ans:
    • 初始化 dp0 = nums[0], dp1 = 0(表示删除 nums[0] 后为空,和为 0),ans = max(dp0, dp1)。
    • 遍历 i=1 到 n-1:
      dp0_new = max(nums[i], dp0 + nums[i])
      dp1_new = max(dp0, dp1 + nums[i]) // dp0 是删除 nums[i] 的情况
      更新 ans = max(ans, dp0_new, dp1_new)
      更新 dp0 = dp0_new, dp1 = dp1_new。
      注意:如果数组全负,ans 可能为 0(如果允许空子数组),但题目可能要求非空,所以最后如果 ans == 0 且 max(nums) < 0,则 ans = max(nums)。
  3. 计算中间段允许删除一次的最小子数组和 min_mid:
    • 初始化 md0 = nums[0], md1 = 0(删除 nums[0] 后中间段为空,和为 0),min_mid = min(md0, md1)。
    • 遍历 i=1 到 n-1:
      md0_new = min(nums[i], md0 + nums[i])
      md1_new = min(md0, md1 + nums[i])
      更新 min_mid = min(min_mid, md0_new, md1_new)
      更新 md0 = md0_new, md1 = md1_new。
  4. 如果 min_mid == total,则跨环和 circ_ans = 线性答案(避免空子数组),否则 circ_ans = total - min_mid。
  5. 最终答案 = max(linear_ans, circ_ans)。
  6. 注意:如果数组长度 n==1,允许删除时子数组可能为空,根据题目要求,如果允许空子数组和为 0,否则为单个元素值。这里假设至少一个元素,且删除后可以为空,所以 n==1 时,删除后为空,和为 0,但最大子数组和应为 max(0, nums[0])。我们按通用逻辑处理即可。

步骤9:例子验证
例:nums = [1, -2, 3, -2],total = 0。
线性 DP:
i=0: dp0=1, dp1=0, ans=1
i=1: dp0_new = max(-2, 1-2) = -1, dp1_new = max(1, 0-2) = 1, ans=max(1,-1,1)=1
i=2: dp0_new = max(3, -1+3) = 3, dp1_new = max(-1, 1+3)=4, ans=4
i=3: dp0_new = max(-2, 3-2)=1, dp1_new = max(3, 4-2)=3, ans=4
linear_ans = 4(子数组 [1,3] 删除 -2)。
中间段最小和:
i=0: md0=1, md1=0, min_mid=0
i=1: md0_new = min(-2, 1-2) = -2, md1_new = min(1, 0-2) = -2, min_mid = min(0,-2,-2) = -2
i=2: md0_new = min(3, -2+3)=1, md1_new = min(-2, -2+3)= -2, min_mid = -2
i=3: md0_new = min(-2, 1-2)= -2, md1_new = min(1, -2-2)= -4, min_mid = -4
min_mid = -4, total - min_mid = 0 - (-4) = 4。
circ_ans = 4。
最终 ans = max(4,4) = 4。
与预期一致。

步骤10:复杂度
时间复杂度 O(n),空间复杂度 O(1),只用了几个变量。
这个题目结合了环形数组、一次删除操作,是区间动态规划的变形,通过状态机 DP 分情况处理。

环形数组中的最大子数组和(限制操作次数) 题目描述 给定一个长度为 n 的环形整数数组 nums,你可以进行最多一次操作:选择数组中任意一个元素,将其修改为任意值(可以变大或变小)。你需要计算在执行最多一次修改操作的情况下,环形数组中的最大子数组和。环形数组意味着子数组可以是跨过数组末尾连接到开头的连续段。 例如,nums = [ 1, -2, 3, -2],在不操作时,最大子数组和为 3(子数组 [ 3]);如果允许一次修改,可以将 -2 改为 100,得到最大子数组和 102(子数组 [ 3, 100 ] 或整个数组)。目标是求出这个最大和。 解题过程循序渐进讲解 这个问题结合了环形数组、子数组和、以及一次修改操作。我们可以分步骤思考。 步骤1:理解基础问题(无环形、无操作) 如果数组不是环形,且不允许修改,最大子数组和是经典问题,可以用 Kadane 算法在 O(n) 时间解决: 定义 dp[ i] 为以 i 结尾的最大子数组和,转移为 dp[ i] = max(nums[ i], dp[ i-1] + nums[ i]),答案为 max(dp[ i ])。 但这里是环形,且允许一次修改,需要更通用的方法。 步骤2:处理环形情况(无操作) 对于环形数组的最大子数组和,有两种可能: 子数组不跨过末尾,即普通的最大子数组和(记作 maxSum)。 子数组跨过末尾,即数组总和减去某个中间段(这个中间段是最小子数组和),因为整个环形数组的和是固定的,跨环最大和 = 总和 - 最小子数组和。 特殊情况:如果所有数都是负数,最大子数组和就是最大单个元素(此时不跨环,因为跨环相当于总和减去一个负数段,会变大,但所有数为负时总和最小,跨环计算可能出错,需特判)。 所以无环形时,答案 = max(maxSum, total - minSum),但需注意当数组全负时,答案就是 max(nums)(即不跨环的情况)。 步骤3:加入一次修改操作 修改一个元素可以影响很多子数组。考虑修改位置 k 的值为 x,那么包含 k 的子数组和会变化。一种思路是:修改一个元素相当于“删除”这个元素对子数组和的贡献,然后替换为新值。但直接枚举修改位置和子数组范围会达到 O(n²)。 我们可以转换思路: 一次修改操作,相当于允许子数组中有一个“断裂点”,在这个点我们可以自由设置值使得子数组和最大。实际上,这等价于:在子数组中,我们可以忽略其中一个元素的贡献(将其视为 0 或任意值来最大化子数组和)。 更形式化地,定义两个 DP 状态: dp1[ i]: 以 i 结尾的子数组, 没有使用修改操作 的最大和。 dp2[ i]: 以 i 结尾的子数组, 已经使用了一次修改操作 的最大和。 对于每个位置 i,我们考虑是否修改 nums[ i ],以及修改操作用在哪里。 步骤4:状态转移方程 我们考虑线性数组(先不考虑环形)的情况,定义: dp1[ i] = max(nums[ i], dp1[ i-1] + nums[ i ]) // 以 i 结尾,未使用修改的最大和 dp2[ i ] 表示以 i 结尾,已经使用过一次修改(修改的可能是 i 或其他位置)的最大和。它可以从几种情况转移: 在 i 位置使用修改,把 nums[ i] 改为任意值,为了最大和,我们可以让它使得子数组和最大,但修改只能一次,且修改后 nums[ i] 的贡献可以任意大吗?题目允许改为任意值,但为了最大化子数组和,如果我们决定在 i 处修改,我们可以将 nums[ i] 改成一个很大的正数,但这样可能会使子数组和无限大?不,因为子数组必须是原数组的连续段,修改只是改变该位置的值,并不增加长度。实际上,如果我们修改 nums[ i],我们可以选择将其改为一个非常大的数,使得包含 i 的子数组和变得非常大,但这样会使得答案依赖于我们设定的值。但注意,题目没有限制修改后的值范围,理论上我们可以改为任意大,那么答案就可能无限大?这不合常理。仔细看题: 环形整数数组 ,一次修改为任意值,但数组元素是整数,修改后的值也应该是整数,但任意值意味着可以很大,那么最大子数组和就可以无限大?这显然不是题目本意。 实际上,常见变形(如 LeetCode 1746. 最大子数组和经过一次修改)中,修改操作是指 你可以将 nums[ i] 替换为 nums[ i] * 2 ,或者类似限制。但这里描述是“修改为任意值”,如果无限制,那么最佳策略是选中整个数组,把最小的负数改为很大的正数,那么最大子数组和就是整个数组的和(修改后全正)。但整个数组的和可能不是最大的,因为还可以选择子数组。但如果我们能修改任意值,我们可以修改某个元素为一个非常大的正数,使得包含它的任何子数组的和都巨大,那么答案就是整个数组的和(修改最小值为极大值)。但这样问题就退化成了:先找数组的总和,然后如果数组中有负数,就把最小的负数改成一个很大的正数,使得总和最大。但这样没有考虑子数组可以只取一部分。 为了避免这种歧义,我们采用更常见的定义: 一次操作允许你将某个元素的值乘以 2 ,或者 一次操作允许你将某个元素替换为另一个任意值,但该值必须在原数组的整数范围内 。但题目没有明确,通常这类问题(如 Max Subarray Sum with One Deletion)是允许 删除 一个元素,而不是任意修改。 这里我们重新理解: 一次修改为任意值 ,实际上等价于 你可以将某个元素替换为任意整数,目的是使得某个子数组和最大 。为了最大化,你会把那个元素改为一个非常大的正数(如果子数组和为正),但这样答案就只取决于你是否能选一个包含修改位置的子数组,然后让修改位置变成一个很大的数,那么最大子数组和就是无限大?显然不合理。 因此,我推测这道题实际上是指 一次删除操作 (LeetCode 1186. Maximum Subarray Sum with One Deletion)的环形版本。但题目描述是“修改”,可能是翻译问题。不过,我们按一次删除操作来解,因为这是经典区间 DP 问题,且你的已讲题目列表中没有此环形版本。 所以我们调整题意: 最多允许删除一个元素(即不将该元素计入子数组),求最大子数组和,数组是环形的 。 步骤5:新题目定义 给定环形整数数组 nums,最多允许从子数组中删除一个元素(即子数组可以不连续一个位置),求最大子数组和(子数组是环形连续段,但允许跳过一个元素)。 例如 nums = [ 1, -2, 3, -2],如果不删除,最大子数组和为 3([ 3]);如果删除 -2,可以得 [ 1, 3 ] 和 4,但环形下可能更好。 步骤6:解决环形+一次删除的问题 我们分解为两个子问题: 不跨环的情况(线性数组):用动态规划求允许删除一个元素的最大子数组和。 跨环的情况:环形数组,子数组跨过末尾,允许删除一个元素。 对于线性情况 : 定义: dp0[ i ]: 以 i 结尾且没有删除过的最大子数组和。 dp1[ i ]: 以 i 结尾且已经删除过一个元素的最大子数组和。 转移: dp0[ i] = max(nums[ i], dp0[ i-1] + nums[ i ]) dp1[ i ] 有两种可能: a) 在 i 处删除,即删除 nums[ i],那么以 i 结尾且删除过的子数组和其实就是 dp0[ i-1](因为 nums[ i ] 被跳过了)。 b) 在之前删除,即包含 nums[ i] 且之前已删除过,所以 dp1[ i] = dp1[ i-1] + nums[ i ]。 此外,还要考虑从 i 开始单独一个元素且之前删除过?不可能,因为删除需要至少一个元素被删。 所以 dp1[ i] = max(dp0[ i-1], dp1[ i-1] + nums[ i]),注意 dp0[ i-1] 表示删除 nums[ i ] 的情况。 初始化:dp0[ 0] = nums[ 0], dp1[ 0] = 0(因为删除 nums[ 0] 后子数组为空,和为 0,但题目允许子数组为空吗?通常不允许,所以 dp1[ 0 ] 可以视为负无穷,表示无效。但为了简化,我们允许空子数组和为 0,但最终答案会取 max,不会只取 0 如果全负)。 线性答案 = max( dp0[ i], dp1[ i ] ) 对所有 i。 对于环形情况 : 环形允许跨过末尾,即子数组由两段组成:[ i..n-1] 和 [ 0..j ] (i > j)。我们需要在这种环形子数组中允许删除一个元素。 环形问题通常的解法是:考虑两种情形: A) 最大子数组不跨环,即上面线性答案。 B) 最大子数组跨环,即总和减去中间一段(中间段是某个子数组,且允许删除一个元素?)。 更具体:跨环子数组的和 = 总和 - 中间段的和。我们要最大化跨环和,就要最小化中间段的和,并且中间段允许删除一个元素(因为整个环形子数组允许删除一个元素,这个删除可以发生在中间段,也可以发生在跨环段,但删除操作只有一次)。 因此,我们需要求: 最小化中间段的和,且中间段允许删除一个元素 。 那么跨环最大和 = 总和 - 中间段最小和(允许删除一次)。 中间段最小和(允许删除一次)可以通过类似线性 DP 求最小子数组和(允许删除一次)得到。 定义: md0[ i ]: 以 i 结尾且没有删除过的最小子数组和。 md1[ i ]: 以 i 结尾且已经删除过一个元素的最小子数组和。 转移: md0[ i] = min(nums[ i], md0[ i-1] + nums[ i ]) md1[ i] = min(md0[ i-1], md1[ i-1] + nums[ i ]) // 删除 i 或在之前删除 初始化类似。 中间段最小和 = min( md0[ i], md1[ i ] ) 对所有 i。 那么跨环最大和 = total - 中间段最小和。 但需要注意:如果中间段是整个数组(即跨环子数组为空),那么跨环和 = 0,这种情况应排除,因为子数组非空。但当我们允许删除时,中间段可能为空吗?中间段为空意味着跨环子数组为整个数组,但删除操作可以用在跨环部分,所以中间段最小和可以是 0(当中间段为空),此时跨环和为 total。但题目允许子数组为空吗?通常要求非空,所以如果 total - 0 = total 且 total 可能为负,我们需小心。不过我们最终会取 max(线性答案, 跨环答案),线性答案至少会选一个元素(除非数组为空)。 步骤7:边界情况处理 全负数数组:线性答案会是最大的单个负数(因为删除一个元素可能得到空数组,如果允许空数组,和为 0 更大;但通常题目不允许空子数组,所以答案就是最大单个数)。我们的 DP 中,dp0 和 dp1 的初始化可能得到 0,我们需要强制子数组非空,可以在计算答案时,如果所有 dp0[ i] 和 dp1[ i ] 都小于 0,则取 max(nums)。 跨环情况:如果中间段最小和等于 total(即中间段为整个数组),那么跨环和为 0,但子数组为空,应排除。所以我们计算跨环答案时,如果中间段最小和 == total,则不考虑跨环情况(因为这意味着跨环子数组为空)。 一次删除操作在环形中,可能删除的元素在跨环段或中间段,但我们的计算中,中间段最小和(允许删除一次)已经考虑了删除在中间段的情况,而跨环段的最大和(即线性部分)没有直接算,因为我们是用 total 减中间段和来得到跨环和,所以删除操作已经被考虑在中间段的最小化中。 注意:一次删除操作在整个环形子数组中只能用一次。所以当我们计算线性部分(不跨环)时,允许一次删除;计算跨环部分时,中间段允许一次删除,但跨环子数组本身不允许再删除(因为总的一次已用在中间段)。这样是正确的,因为如果删除操作用在跨环段,那么相当于中间段没有删除,但中间段最小和(不允许删除)可能更大,这样 total - 中间段和会更小,不是最大。所以为了最大化跨环和,我们会将删除用在中间段(使中间段和更小),除非删除用在跨环段能使得跨环和更大,但跨环和是两段的和,删除一个元素可能增加跨环和吗?可能,比如跨环段中有一个负数,删除它后跨环和变大。但我们的计算中,跨环和 = total - 中间段和,如果删除用在跨环段,相当于中间段没有删除,但 total 不变,中间段和可能更大,导致跨环和更小。所以最优解中,删除操作一定用在中间段(如果我们选择跨环子数组)。因此,我们的分情况是合理的。 步骤8:算法步骤 计算数组总和 total。 线性 DP 计算不跨环且允许删除一次的最大子数组和 linear_ ans: 初始化 dp0 = nums[ 0], dp1 = 0(表示删除 nums[ 0 ] 后为空,和为 0),ans = max(dp0, dp1)。 遍历 i=1 到 n-1: dp0_ new = max(nums[ i], dp0 + nums[ i ]) dp1_ new = max(dp0, dp1 + nums[ i]) // dp0 是删除 nums[ i ] 的情况 更新 ans = max(ans, dp0_ new, dp1_ new) 更新 dp0 = dp0_ new, dp1 = dp1_ new。 注意:如果数组全负,ans 可能为 0(如果允许空子数组),但题目可能要求非空,所以最后如果 ans == 0 且 max(nums) < 0,则 ans = max(nums)。 计算中间段允许删除一次的最小子数组和 min_ mid: 初始化 md0 = nums[ 0], md1 = 0(删除 nums[ 0] 后中间段为空,和为 0),min_ mid = min(md0, md1)。 遍历 i=1 到 n-1: md0_ new = min(nums[ i], md0 + nums[ i ]) md1_ new = min(md0, md1 + nums[ i ]) 更新 min_ mid = min(min_ mid, md0_ new, md1_ new) 更新 md0 = md0_ new, md1 = md1_ new。 如果 min_ mid == total,则跨环和 circ_ ans = 线性答案(避免空子数组),否则 circ_ ans = total - min_ mid。 最终答案 = max(linear_ ans, circ_ ans)。 注意:如果数组长度 n==1,允许删除时子数组可能为空,根据题目要求,如果允许空子数组和为 0,否则为单个元素值。这里假设至少一个元素,且删除后可以为空,所以 n==1 时,删除后为空,和为 0,但最大子数组和应为 max(0, nums[ 0 ])。我们按通用逻辑处理即可。 步骤9:例子验证 例:nums = [ 1, -2, 3, -2 ],total = 0。 线性 DP: i=0: dp0=1, dp1=0, ans=1 i=1: dp0_ new = max(-2, 1-2) = -1, dp1_ new = max(1, 0-2) = 1, ans=max(1,-1,1)=1 i=2: dp0_ new = max(3, -1+3) = 3, dp1_ new = max(-1, 1+3)=4, ans=4 i=3: dp0_ new = max(-2, 3-2)=1, dp1_ new = max(3, 4-2)=3, ans=4 linear_ ans = 4(子数组 [ 1,3 ] 删除 -2)。 中间段最小和: i=0: md0=1, md1=0, min_ mid=0 i=1: md0_ new = min(-2, 1-2) = -2, md1_ new = min(1, 0-2) = -2, min_ mid = min(0,-2,-2) = -2 i=2: md0_ new = min(3, -2+3)=1, md1_ new = min(-2, -2+3)= -2, min_ mid = -2 i=3: md0_ new = min(-2, 1-2)= -2, md1_ new = min(1, -2-2)= -4, min_ mid = -4 min_ mid = -4, total - min_ mid = 0 - (-4) = 4。 circ_ ans = 4。 最终 ans = max(4,4) = 4。 与预期一致。 步骤10:复杂度 时间复杂度 O(n),空间复杂度 O(1),只用了几个变量。 这个题目结合了环形数组、一次删除操作,是区间动态规划的变形,通过状态机 DP 分情况处理。