You are given an integer array nums
of even length n
and an integer limit
. In one move, you can replace any integer from nums
with another integer between 1
and limit
, inclusive.
The array nums
is complementary if for all indices i
(0-indexed), nums[i] + nums[n - 1 - i]
equals the same number. For example, the array [1,2,3,4]
is complementary because for all indices i
, nums[i] + nums[n - 1 - i] = 5
.
Return the minimum number of moves required to make nums
complementary.
Example 1:
Input: nums = [1,2,4,3], limit = 4 Output: 1 Explanation: In 1 move, you can change nums to [1,2,2,3] (underlined elements are changed). 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. Therefore, nums[i] + nums[n-1-i] = 4 for every i, so nums is complementary.
Example 2:
Input: nums = [1,2,2,1], limit = 2 Output: 2 Explanation: In 2 moves, you can change nums to [2,2,2,2]. You cannot change any number to 3 since 3 > limit.
Example 3:
Input: nums = [1,2,1,2], limit = 2 Output: 0 Explanation: nums is already complementary.
Constraints:
n == nums.length
2 <= n <= 105
1 <= nums[i] <= limit <= 105
n
is even.
Related Topics:
Greedy
Assume we want to make all the pairs to sum to T
, and (A, B)
is a pair of numbers. We have the following cases:
2 <= T <= min(A, B)
. We need2
operations because we need to make both smaller.min(A, B) < T < A + B
. We need1
operation because we only need to make the greater one smaller.T == A + B
. We need0
operation.A + B < T <= max(A, B) + limit
. We need1
operation because we only need to make the smaller one greater.max(A, B) + limit < T <= 2 * limit
. We need2
operations because we need to make both greater.
We can calculate the boundary for each pair (A, B)
and note down the corresponding operation needed in cnt
array where cnt[i]
means that we need cnt[i]
operations when T == i
.
We need to use the above 5 cases to add values into cnt
.
For each pair (A, B)
, we do the following:
cnt[i] += 2
if2 <= i <= min(A, B)
cnt[i] += 1
ifmin(A, B) < i < A + B
cnt[i] += 0
ifi == A + B
cnt[i] += 1
ifA + B < i <= max(A, B) + limit
cnt[i] += 2
ifmax(A, B) + limit < T <= 2 * limit
But for each pair we need to visit 2 * limit - 2
elements in cnt
, and there are N / 2
pairs, so the time complexity is O(NL)
which will get TLE.
To resolve this, we can make it a difference array, i.e. only save the difference of operations when we move from i - 1
to i
.
Assume the difference array is delta
, where delta[i] = cnt[i] - cnt[i - 1]
, i.e. the difference of operations needed when changing T
from i - 1
to i
.
For example, delta[3] = 1
means that if we change T
from 2
to 3
, we need one more operation.
So in this way, we don't need to change all 2 * limit - 2
elements. Instead, just change 5 break points:
delta[2] += 2
.delta[min(A, B) + 1] -= 1
.delta[A + B] -= 1
.delta[A + B + 1] += 1
.delta[max(A, B) + limit + 1] += 1
.
And in the end we just need to go over the 2 * limit - 2
elements to get the operations needed for each T
, and return the minimum among them.
Calculating the delta
array takes O(N)
time. Reconstructing the cnt
s from delta
takes O(L)
time. So overall it's O(N + L)
time.
// OJ: https://leetcode.com/problems/minimum-moves-to-make-array-complementary/
// Author: github.com/lzl124631x
// Time: O(N + L)
// Space: O(L)
// Ref: https://leetcode.com/problems/minimum-moves-to-make-array-complementary/discuss/952773/PythonJava-simple-O(max(n-k))-method
class Solution {
public:
int minMoves(vector<int>& A, int L) {
vector<int> delta(2 * L + 2); // difference array
int N = A.size(), ans = N, cur = 0;
for (int i = 0; i < N / 2; ++i) {
int a = A[i], b = A[N - i - 1];
delta[2] += 2;
delta[min(a, b) + 1]--;
delta[a + b]--;
delta[a + b + 1]++;
delta[max(a, b) + L + 1]++;
}
for (int i = 2; i <= 2 * L; ++i) {
cur += delta[i];
ans = min(ans, cur);
}
return ans;
}
};