环形数组的最小代价划分问题
字数 2889 2025-12-05 20:53:00

环形数组的最小代价划分问题

题目描述
给定一个环形数组 nums,其长度为 n。你可以执行以下操作任意次:选择数组中任意一个元素,将其移除,并支付该元素的代价。你的目标是最终将数组划分成若干个“好段”。一个“好段”定义为长度恰好为 k 的连续子数组(在原数组剩余元素顺序不变的前提下)。注意,由于数组是环形的,头尾元素被认为是相邻的。问:为了将数组划分成若干个“好段”(允许最后剩下无法构成好段的零散元素,但需要将它们全部移除),你需要支付的最小总代价是多少?

例如,假设 nums = [1, 2, 3, 4, 5], k = 2。一种方案是:移除元素 1,则剩下 [2, 3, 4, 5],可以划分为 [2, 3][4, 5] 两个好段,代价为 1。另一种方案是:移除元素 3,剩下 [1, 2, 4, 5],但无法形成长度为 2 的好段(因为 1 和 5 相邻,但移除 3 后它们不相邻),还需要继续移除,总代价可能更高。题目要求找到最小总代价。


解题步骤

  1. 问题转换
    由于数组是环形的,处理起来比线性数组复杂。常见的技巧是“破环成链”:将原数组复制一份接在后面,形成长度为 2n 的线性数组。这样,环形中任意一段连续子数组(可能跨越头尾)都对应新线性数组中长度为 n 以内的某个连续子数组。
    但注意,我们划分好段时,最终剩下的元素(未被划分的)会被移除。我们可以反过来思考:最大化保留的元素总价值(因为总代价 = 所有元素代价之和 - 保留元素代价之和),并且保留的元素必须构成若干个互不重叠的长度为 k 的段。由于是环形,这些段在环上排列,不会重叠。

  2. 定义状态
    dp[i] 表示在线性数组(即破环成链后的数组)中,考虑前 i 个元素(下标从 1 开始),在选取若干长度为 k 的不重叠段(每段必须完整保留,不能只取部分)的情况下,能够保留的最大代价和。
    注意,这里“保留”意味着这些段最终不被移除,且它们之间可以有空隙(空隙中的元素会被移除)。
    由于段长度固定为 k,状态转移时,我们考虑是否以 i 结尾形成一个好段:

    • 如果不选取以 i 结尾的段,则 dp[i] = dp[i-1]
    • 如果选取以 i 结尾的段,则该段为 [i-k+1, i],需要保留这个段的所有元素,那么 dp[i] = dp[i-k] + sum(nums[i-k+1 ... i]),其中 sum 表示这一段的和。
      因此:
    dp[i] = max(dp[i-1], dp[i-k] + sum(nums[i-k+1 ... i]))   (当 i >= k 时)
    

    初始时,dp[0] = 0,且对于 i < k,不能形成完整段,dp[i] = 0

  3. 处理环形
    在环形中,如果我们选取了一些好段,这些段在环上排列,那么环上会剩下一些未被覆盖的元素。由于环形,我们可以认为第一个元素是否被保留会影响结构。
    一种巧妙方法:

    • 情况一:第一个元素不被保留(即被移除)。那么问题转化为在 nums[2..n] 这个线性数组上选取若干好段,求最大保留和。
    • 情况二:第一个元素被保留。那么它必须属于某个好段,由于段长度为 k,这个段必须包含 nums[1..k](因为第一个元素是段的首元素)。那么 nums[1..k] 被保留,接下来在 nums[k+1..n] 这个线性数组中继续选取好段。
      这样,我们枚举这两种情况,分别用上述线性 DP 求解,再取最优。
  4. 实现细节

    • 预处理前缀和 prefix,方便快速求区间和。
    • 对情况一:在线性数组 nums[2..n] 上运行 DP,注意数组长度为 n-1
    • 对情况二:强制保留 nums[1..k],然后在 nums[k+1..n] 上运行 DP,数组长度为 n-k
    • 总代价 = 所有元素和 - 最大保留和。
  5. 边界情况

    • 如果 k > n,无法形成任何好段,最小代价就是所有元素代价和(全部移除)。
    • 如果 k == 1,每个元素自身就是一个好段,可以保留所有元素,代价为 0。
    • 注意在情况二中,必须满足 k <= n,否则无法保留第一个元素所在段。
  6. 示例演算
    nums = [1, 2, 3, 4, 5], k = 2 为例:
    总代价和 = 15。
    情况一:第一个元素移除,在线性数组 [2,3,4,5] 上 DP:

    • 前缀和:[0,2,5,9,14]
    • dp[1]=0, dp[2]=max(0, dp[0]+sum(2,3)=5)=5dp[3]=max(5, dp[1]+sum(3,4)=7)=7dp[4]=max(7, dp[2]+sum(4,5)=9)=9
      最大保留和 = 9,对应保留段 [2,3][4,5]
      情况二:保留第一个元素所在段 [1,2],和在 [3,4,5] 上 DP:
    • 数组 [3,4,5] 上 DP:dp[1]=0, dp[2]=max(0, dp[0]+sum(3,4)=7)=7dp[3]=max(7, dp[1]+sum(4,5)=9)=9
      最大保留和 = 1+2 + 9 = 12(保留 [1,2][4,5])。
      比较两种情况,最大保留和 = max(9, 12) = 12。
      最小总代价 = 15 - 12 = 3。
      注意这里比直接移除元素 1 的代价 1 更大?检查:移除 1 后剩下 [2,3,4,5],可划分 [2,3][4,5],保留和 = 2+3+4+5=14,代价=1。为什么我们 DP 得到 12?因为情况一我们计算的是在线性数组 [2,3,4,5] 上,保留两段 [2,3][4,5] 的和是 14,但我们的 DP 数组求得是 9,哪里错了?
      错误在于:在线性数组 [2,3,4,5] 中,dp[4] 应该是 max(dp[3], dp[2]+sum(4,5)=9),而 dp[2]=5, dp[3]=max(5, dp[1]+7)=7,所以 dp[4]=max(7, 5+9=14)=14。我前面计算错了 dp[2] 的值,更正:
      dp[2] = max(dp[1], dp[0]+sum(2,3)=5) = max(0,5) = 5
      dp[3] = max(dp[2], dp[1]+sum(3,4)=7) = max(5,7) = 7
      dp[4] = max(dp[3], dp[2]+sum(4,5)=9) = max(7, 5+9=14) = 14
      所以情况一最大保留和 = 14,情况二 = 12,最优为 14,代价 = 15-14=1。符合预期。
  7. 最终答案
    综合两种情况,得到最大保留和,再用总和减去即得最小代价。
    时间复杂度 O(n),空间复杂度 O(n)。


通过以上步骤,我们可以系统解决这类环形数组固定长度段划分的最小代价问题。核心是破环处理 + 固定长度段选取的线性 DP。

环形数组的最小代价划分问题 题目描述 给定一个环形数组 nums ,其长度为 n 。你可以执行以下操作任意次:选择数组中任意一个元素,将其移除,并支付该元素的代价。你的目标是最终将数组划分成若干个“好段”。一个“好段”定义为长度恰好为 k 的连续子数组(在原数组剩余元素顺序不变的前提下)。注意,由于数组是环形的,头尾元素被认为是相邻的。问:为了将数组划分成若干个“好段”(允许最后剩下无法构成好段的零散元素,但需要将它们全部移除),你需要支付的最小总代价是多少? 例如,假设 nums = [1, 2, 3, 4, 5] , k = 2 。一种方案是:移除元素 1,则剩下 [2, 3, 4, 5] ,可以划分为 [2, 3] 和 [4, 5] 两个好段,代价为 1。另一种方案是:移除元素 3,剩下 [1, 2, 4, 5] ,但无法形成长度为 2 的好段(因为 1 和 5 相邻,但移除 3 后它们不相邻),还需要继续移除,总代价可能更高。题目要求找到最小总代价。 解题步骤 问题转换 由于数组是环形的,处理起来比线性数组复杂。常见的技巧是“破环成链”:将原数组复制一份接在后面,形成长度为 2n 的线性数组。这样,环形中任意一段连续子数组(可能跨越头尾)都对应新线性数组中长度为 n 以内的某个连续子数组。 但注意,我们划分好段时,最终剩下的元素(未被划分的)会被移除。我们可以反过来思考:最大化保留的元素总价值(因为总代价 = 所有元素代价之和 - 保留元素代价之和),并且保留的元素必须构成若干个互不重叠的长度为 k 的段。由于是环形,这些段在环上排列,不会重叠。 定义状态 设 dp[i] 表示在线性数组(即破环成链后的数组)中,考虑前 i 个元素(下标从 1 开始),在选取若干长度为 k 的不重叠段(每段必须完整保留,不能只取部分)的情况下,能够保留的最大代价和。 注意,这里“保留”意味着这些段最终不被移除,且它们之间可以有空隙(空隙中的元素会被移除)。 由于段长度固定为 k ,状态转移时,我们考虑是否以 i 结尾形成一个好段: 如果不选取以 i 结尾的段,则 dp[i] = dp[i-1] 。 如果选取以 i 结尾的段,则该段为 [i-k+1, i] ,需要保留这个段的所有元素,那么 dp[i] = dp[i-k] + sum(nums[i-k+1 ... i]) ,其中 sum 表示这一段的和。 因此: 初始时, dp[0] = 0 ,且对于 i < k ,不能形成完整段, dp[i] = 0 。 处理环形 在环形中,如果我们选取了一些好段,这些段在环上排列,那么环上会剩下一些未被覆盖的元素。由于环形,我们可以认为第一个元素是否被保留会影响结构。 一种巧妙方法: 情况一:第一个元素不被保留(即被移除)。那么问题转化为在 nums[2..n] 这个线性数组上选取若干好段,求最大保留和。 情况二:第一个元素被保留。那么它必须属于某个好段,由于段长度为 k ,这个段必须包含 nums[1..k] (因为第一个元素是段的首元素)。那么 nums[1..k] 被保留,接下来在 nums[k+1..n] 这个线性数组中继续选取好段。 这样,我们枚举这两种情况,分别用上述线性 DP 求解,再取最优。 实现细节 预处理前缀和 prefix ,方便快速求区间和。 对情况一:在线性数组 nums[2..n] 上运行 DP,注意数组长度为 n-1 。 对情况二:强制保留 nums[1..k] ,然后在 nums[k+1..n] 上运行 DP,数组长度为 n-k 。 总代价 = 所有元素和 - 最大保留和。 边界情况 如果 k > n ,无法形成任何好段,最小代价就是所有元素代价和(全部移除)。 如果 k == 1 ,每个元素自身就是一个好段,可以保留所有元素,代价为 0。 注意在情况二中,必须满足 k <= n ,否则无法保留第一个元素所在段。 示例演算 以 nums = [1, 2, 3, 4, 5] , k = 2 为例: 总代价和 = 15。 情况一:第一个元素移除,在线性数组 [2,3,4,5] 上 DP: 前缀和:[ 0,2,5,9,14 ] dp[1]=0 , dp[2]=max(0, dp[0]+sum(2,3)=5)=5 , dp[3]=max(5, dp[1]+sum(3,4)=7)=7 , dp[4]=max(7, dp[2]+sum(4,5)=9)=9 。 最大保留和 = 9,对应保留段 [2,3] 和 [4,5] 。 情况二:保留第一个元素所在段 [1,2] ,和在 [3,4,5] 上 DP: 数组 [3,4,5] 上 DP: dp[1]=0 , dp[2]=max(0, dp[0]+sum(3,4)=7)=7 , dp[3]=max(7, dp[1]+sum(4,5)=9)=9 。 最大保留和 = 1+2 + 9 = 12(保留 [1,2] 和 [4,5] )。 比较两种情况,最大保留和 = max(9, 12) = 12。 最小总代价 = 15 - 12 = 3。 注意这里比直接移除元素 1 的代价 1 更大?检查:移除 1 后剩下 [2,3,4,5] ,可划分 [2,3] 和 [4,5] ,保留和 = 2+3+4+5=14,代价=1。为什么我们 DP 得到 12?因为情况一我们计算的是在线性数组 [2,3,4,5] 上,保留两段 [2,3] 和 [4,5] 的和是 14,但我们的 DP 数组求得是 9,哪里错了? 错误在于:在线性数组 [2,3,4,5] 中, dp[4] 应该是 max(dp[3], dp[2]+sum(4,5)=9) ,而 dp[2]=5 , dp[3]=max(5, dp[1]+7)=7 ,所以 dp[4]=max(7, 5+9=14)=14 。我前面计算错了 dp[2] 的值,更正: dp[2] = max(dp[1], dp[0]+sum(2,3)=5) = max(0,5) = 5 。 dp[3] = max(dp[2], dp[1]+sum(3,4)=7) = max(5,7) = 7 。 dp[4] = max(dp[3], dp[2]+sum(4,5)=9) = max(7, 5+9=14) = 14 。 所以情况一最大保留和 = 14,情况二 = 12,最优为 14,代价 = 15-14=1。符合预期。 最终答案 综合两种情况,得到最大保留和,再用总和减去即得最小代价。 时间复杂度 O(n),空间复杂度 O(n)。 通过以上步骤,我们可以系统解决这类环形数组固定长度段划分的最小代价问题。核心是破环处理 + 固定长度段选取的线性 DP。