3224. 使差值相等的最少数组改动次数
给你一个长度为\(n\)的整数数组\(nums\),\(n\)是 偶数 ,同时给你一个整数\(k\) 。
你可以对数组进行一些操作。每次操作中,你可以将数组中 任一 元素替换为\(0\)到\(k\)之间的 任一 整数。
执行完所有操作以后,你需要确保最后得到的数组满足以下条件:
存在一个整数\(X\),满足对于所有的 \((0 <= i < n)\) 都有\(abs(a[i] - a[n - i - 1]) = X\)。
请你返回满足以上条件 最少 修改次数。
示例 1:
输入:nums = [1,0,1,2,4,3], k = 4
输出:2
解释:
我们可以执行以下操作:
将 nums[1] 变为 2 ,结果数组为 nums = [1,2,1,2,4,3] 。
将 nums[3] 变为 3 ,结果数组为 nums = [1,2,1,3,4,3] 。
整数 X 为 2 。
示例 2:
输入:nums = [0,1,2,3,3,6,5,4], k = 6
输出:2
解释:
我们可以执行以下操作:
将 nums[3] 变为 0 ,结果数组为 nums = [0,1,2,0,3,6,5,4] 。
将 nums[4] 变为 4 ,结果数组为 nums = [0,1,2,0,4,6,5,4] 。
整数 X 为 4 。
提示:
\(2 <= n == nums.length <= 10^5\)
n 是偶数。
\(0 <= nums[i] <= k <= 10^5\)
注意到每一对数不会互相影响,所以可以把每一对数分开考虑。
设一对数中,一个是\(a\),一个是\(b\),那么改掉其中一个数可以获得的最大差值,肯定是把另一个数改成 0 或 k,即最大差值\(m=max(a,k−a,b,k−b)\)。改掉两个数,那就可以获得从\(0\)到\(k\)里的任意差值。
所以对于这一对数来说,\(X=∣a−b∣\)时不需要操作,\(0≤X<∣a−b∣\)以及\(∣a−b∣<X≤m\) 时需要一次操作,\(X>m\)时需要两次操作。
枚举所有数对,用差分数组维护\(X\)的某个取值需要几次操作即可。复杂度 \(O(n+k)\)。
- 就是我们令\(d=abs(nums[i]-nums[j])\)。就是假如最后的这个\(0≤ X <|a−b∣\),那么就可以通过一次操作完成。
- 操作一次能达到的最大差值是多少呢?这个就是上面说的肯定是把另一个数改成 0 或 k。即最大差值为\(m=max(a,k−a,b,k−b)\)。那么就是\(∣a−b∣<X≤m\) 时需要一次操作。
- 剩下就是\(X>m\)时需要两次操作。
之后就是把那三种情况差分一下就行。然后取最小的就行。
class Solution {
public:
int minChanges(vector<int>& nums, int k) {
int n=nums.size();
vector<int>f(k+2,0);
for(int i=0,j=n-1;i<j;i++,j--){
int d=abs(nums[i]-nums[j]);
int ma=max({nums[i],k-nums[i],nums[j],k-nums[j]});
// 0 <= x < d 时需要一次操作
f[0]++; f[d]--;
// d < x <= mx 时需要一次操作
f[d + 1]++; f[ma + 1]--;
// x > mx 时需要两次操作
f[ma + 1] += 2;
}
int ans=f[0];
for(int i=1;i<=k+1;i++){
f[i]+=f[i-1];
ans=min(ans,f[i]);
}
return ans;
}
};