给你一个长度为 偶数 n
的整数数组 nums
和一个整数 limit
。每一次操作,你可以将 nums
中的任何整数替换为 1
到 limit
之间的另一个整数。
如果对于所有下标 i
(下标从 0
开始),nums[i] + nums[n - 1 - i]
都等于同一个数,则数组 nums
是 互补的 。例如,数组 [1,2,3,4]
是互补的,因为对于所有下标 i
,nums[i] + nums[n - 1 - i] = 5
。
返回使数组 互补 的 最少 操作次数。
示例 1:
输入:nums = [1,2,4,3], limit = 4 输出:1 解释:经过 1 次操作,你可以将数组 nums 变成 [1,2,2,3](加粗元素是变更的数字): nums[0] + nums[3] = 1 + 3 = 4. nums[1] + nums[2] = 2 + 2 = 4. nums[2] + nums[1] = 2 + 2 = 4. nums[3] + nums[0] = 3 + 1 = 4. 对于每个 i ,nums[i] + nums[n-1-i] = 4 ,所以 nums 是互补的。
示例 2:
输入:nums = [1,2,2,1], limit = 2 输出:2 解释:经过 2 次操作,你可以将数组 nums 变成 [2,2,2,2] 。你不能将任何数字变更为 3 ,因为 3 > limit 。
示例 3:
输入:nums = [1,2,1,2], limit = 2 输出:0 解释:nums 已经是互补的。
提示:
n == nums.length
2 <= n <= 10^5
1 <= nums[i] <= limit <= 10^5
n
是偶数。
提示 1
Given a target sum x, each pair of nums[i] and nums[n-1-i] would either need 0, 1, or 2 modifications.
提示 2
Can you find the optimal target sum x value such that the sum of modifications is minimized?
提示 3
Create a difference array to efficiently sum all the modifications.
解法1:差分数组
提示 1
给定目标总和 x,nums[i] 和 nums[n-1-i] 的每一对需要修改 0、1 或 2 次。
提示 2
你能找到使修改次数最小的最优目标总和 x 值吗?
提示 3
创建一个差值数组来有效地求和所有修改。
对于每对元素(a, b),最多2次操作,就可以变成所有可能变成的和了。因此一共有3种情况:
- 0次操作只能达成原本的和。[a+b]
- 1次操作的下限为:将较大值变为1,加上较小值的和;上限为:将较小值变为limit,加上较大值的和。[1 + min(a, b), limit + max(a, b)]
- 2次操作的下限为2,上限为limit * 2。[2, limit * 2]
2 <= 1 + min(a,b) <= a + b <= limit + max(a, b) <= limit * 2
- [2, 1 + min(a,b) ) 最少需要 2 次操作,
- [1 + min(a, b), a + b) 最少需要 1 次操作,
- [a + b] 最少需要 0 次操作,
- (a + b, limit + max(a, b)] 最少需要 1 次操作,
- (limit + max(a, b), limit * 2]最少需要 2 次操作。
我们将每对元素达到某个和需要的最少操作数加在一起,就是总的最少操作数,因此这题相当于区间相加问题,可以用差分数组解决。
Java版:
class Solution {
public int minMoves(int[] nums, int limit) {
int n = nums.length;
int[] diff = new int[2 * limit + 2];
for (int i = 0; i + i < n; i++) {
int a = nums[i];
int b = nums[n - 1 - i];
// 2 <= 1 + min(a,b) <= a + b <= limit + max(a, b) <= limit * 2
diff[2] += 2;
diff[1 + Math.min(a, b)] -= 1;
diff[a + b] -= 1;
diff[a + b + 1] += 1;
diff[limit + Math.max(a, b) + 1] += 1;
}
int ans = Integer.MAX_VALUE;
for (int i = 2; i <= 2 * limit; i++) {
diff[i] += diff[i - 1];
ans = Math.min(diff[i], ans);
}
return ans;
}
}
Python3版:
class Solution:
def minMoves(self, nums: List[int], limit: int) -> int:
n = len(nums)
diff = [0] * (limit * 2 + 2)
for i in range(n // 2):
a = nums[i]
b = nums[n - 1 - i]
# 2 < 1 + min(a, b) < a + b < limit + max(a, b) < limit * 2
diff[2] += 2
diff[1 + min(a, b)] -= 1
diff[a + b] -= 1
diff[a + b + 1] += 1
diff[limit + max(a, b) + 1] += 1
ans = inf
for i in range(2, limit * 2 + 1):
diff[i] += diff[i - 1]
ans = min(ans, diff[i])
return ans
复杂度分析
- 时间复杂度:O(n),n 为数组 nums 的长度。
- 空间复杂度:O(limit),limit 为输入值。