环形数组的最小代价划分问题
题目描述
给定一个环形数组 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[i] = max(dp[i-1], dp[i-k] + sum(nums[i-k+1 ... i])) (当 i >= k 时)初始时,
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。