目录
LeetCode 1674 | 使数组互补的最少操作次数
题目描述
给你一个长度为偶数 n 的整数数组 nums 和一个整数 limit。你可以对数组执行若干次操作,每次操作可以将数组中的任意元素替换成 [1, limit] 范围内的另一个整数。
我们称数组是 互补的,如果对于所有的下标 i(0-based),满足:
nums[i] + nums[n - 1 - i] == 同一个定值
也就是说,对称位置的元素对之和都是同一个数字。
请你返回使数组互补的 最少操作次数。
题目示例
举个例子:
输入:
nums = [1, 2, 3, 4]
limit = 4
输出:1
解释:
原数组对称和分别是 nums[0]+nums[3] = 1+4=5,nums[1]+nums[2] = 2+3=5,
已经相等,替换次数为0。
但是如果是 nums = [1, 2, 2, 4],要使两对和相等,最少替换次数为1,
例如将 nums[2] 替换成 3,使数组变为 [1, 2, 3, 4],两对和都为5。
解题分析
题目要求让对称位置的元素对 (nums[i], nums[n-1-i]) 的和相同,我们可以将数组划分为 n/2 个对。
对每对 (a, b),我们希望替换操作尽可能少,使它们的和达到某个目标值 x。问题的关键:
- 目标和
x是一个待选的值,我们需要找到使总替换次数最小的x。 - 替换操作中,每个元素可以替换为
[1, limit]之间的任意值。 - 替换次数对每对
(a,b)最多为2次(替换两个元素)。
关键思路
对每对 (a,b),替换次数依据目标和 x 有三种情况:
- 0 次替换:如果
a + b == x,不需要任何替换。 - 1 次替换:如果可以通过替换其中一个元素,使和为
x,例如替换a为x - b,且x - b在[1, limit]内。 - 2 次替换:否则,必须替换两个元素。
这意味着,每个对 (a,b) 对目标和 x 的替换次数是:
- 0,若
x == a+b - 1,若
x在[1 + min(a,b), limit + max(a,b)]范围内但不等于a+b - 2,其他情况
差分数组 + 区间更新的巧妙解法
因为 x 的范围是 [2, 2*limit],我们可以统计对每个可能的目标和 x 替换总次数。
对每对 (a,b),替换次数随 x 的变化形态如下:
| x范围 | 替换次数 |
|
| 0 |
|
且 | 1 |
| 其他 | 2 |
用差分数组表示替换次数变化:
- 初始全部为 2 次(全部替换)
- 对区间
[low, high] = [1 + min(a,b), limit + max(a,b)]替换次数减少 1 - 对单点
a+b替换次数再减少 1
利用差分数组对区间和点进行加减标记,最后对差分数组求前缀和即可得到每个和 x 的总替换次数。
代码实现
from typing import List
class Solution:
def minMoves(self, nums: List[int], limit: int) -> int:
n = len(nums)
change = [0] * (2 * limit + 2)
for i in range(n // 2):
a = nums[i]
b = nums[n - 1 - i]
low = 1 + min(a, b)
high = limit + max(a, b)
sum_ab = a + b
# 初始替换次数为 2
change[2] += 2
# 区间内替换次数减少 1
change[low] -= 1
change[high + 1] += 1
# 和为 sum_ab 替换次数再减少 1
change[sum_ab] -= 1
change[sum_ab + 1] += 1
# 计算前缀和,得到每个和 x 的总替换次数
for i in range(2, 2 * limit + 1):
change[i] += change[i - 1]
# 返回最小替换次数
return min(change[2:2*limit+1])
复杂度分析
- 时间复杂度:O(n + limit),其中
n是数组长度,limit是元素最大值。 - 空间复杂度:O(limit),用来存储差分数组。
示例说明
以 nums = [1, 2, 2, 4],limit = 4 为例:
- 对称对是
(1,4)和(2,2)。 (1,4)的和是 5,low = 1 + 1 = 2,high = 4 + 4 = 8。(2,2)的和是 4,low = 1 + 2 = 3,high = 4 + 2 = 6。
对于所有可能和 x ∈ [2, 8],计算替换次数:
- 目标和为5:
-
(1,4)替换次数为0(和为5)(2,2)替换次数为1(需要替换一个元素把4变为5)- 总计 1 次替换。
- 目标和为4:
-
(1,4)替换次数为1(替换一个元素)(2,2)替换次数为0- 总计 1 次替换。
取最小替换次数为 1,和我们的直观分析一致。
总结与思考
- 这题的难点在于找到如何快速计算所有可能目标和
x对应的替换次数,而不是对每个x都遍历所有对。 - 差分数组(区间更新)是实现这一点的关键技巧,大幅降低时间复杂度。
- 该方法也体现了区间计数与前缀和思想在竞赛算法中的典型应用。
LeetCode 1674:使数组互补最少操作次数
1184

被折叠的 条评论
为什么被折叠?



