Given an array nums
of even length n
and an integer limit
, you are to make the array complementary.
An array is complementary if for every pair (nums[i], nums[n - 1 - i])
(for all i
from 0
to n/2 - 1
), the sum is equal to the same value for every pair.
For each pair, you are allowed to change either or both numbers to any integer in the range [1, limit]
. Changing a number counts as one move. Return the minimum total moves needed to make the array complementary.
2 <= n <= 10^5
, 1 <= limit <= 10^5
, 1 <= nums[i] <= limit
, n
is even.
At first glance, a brute-force approach would check every possible target sum for all pairs, and for each, count the moves needed. But with large n
and limit
, this is not feasible.
We need to figure out, for each possible sum S
(from 2
to 2 * limit
), how many moves it would take to make every pair's sum equal to S
. For a pair (a, b)
, we notice:
a + b == S
, no moves are needed.S
(and it's within [1, limit]
), that's one move.S
without iterating over all pairs for each S
.
This leads us to an interval/difference array approach, where we can efficiently count the number of pairs requiring 0, 1, or 2 moves for each possible sum.
(nums[i], nums[n-1-i])
for i
from 0
to n/2-1
.(a, b)
:
a + b
needs 0 moves if we target that sum.[min(a, b)+1, max(a, b)+limit]
using one move.diff
of size 2 * limit + 2
to efficiently track, for each possible sum S
, the number of additional moves needed.diff[2]
by 2 (every sum starts with 2 moves by default).diff[min(a, b)+1]
by 1 (from this point, only 1 move is needed).diff[a+b]
by 1 (from this point, 0 moves are needed).diff[a+b+1]
by 1 (exit 0 move interval, back to 1 move).diff[max(a, b)+limit+1]
by 1 (exit 1 move interval, back to 2 moves).diff
to get the number of moves needed for each possible sum S
.This approach is efficient because it processes all pairs in O(n) time and computes the result for all possible sums in O(limit) time.
Suppose nums = [1,2,4,3]
, limit = 4
. The pairs are (1,3)
and (2,4)
.
a=1
, b=3
a=2
, b=4
We use the difference array as described. After processing both pairs and computing prefix sums, we find for each possible sum (from 2 to 8) the number of moves required. The minimum is 1, which is the answer.
We efficiently solve the "Minimum Moves to Make Array Complementary" problem by leveraging a difference array to track the number of moves needed for each possible target sum. By analyzing the range of sums achievable with 0, 1, or 2 moves for each pair, and aggregating this information, we avoid brute-force enumeration and achieve an O(n + limit) solution. This approach highlights the power of interval counting and prefix sums in optimizing problems involving ranges and cumulative effects.
class Solution:
def minMoves(self, nums: List[int], limit: int) -> int:
n = len(nums)
diff = [0] * (2 * limit + 2)
for i in range(n // 2):
a, b = nums[i], nums[n - 1 - i]
low = 1 + min(a, b)
high = limit + max(a, b)
s = a + b
diff[2] += 2
diff[low] -= 1
diff[s] -= 1
diff[s + 1] += 1
diff[high + 1] += 1
res = float('inf')
curr = 0
for S in range(2, 2 * limit + 1):
curr += diff[S]
res = min(res, curr)
return res
class Solution {
public:
int minMoves(vector<int>& nums, int limit) {
int n = nums.size();
vector<int> diff(2 * limit + 2, 0);
for (int i = 0; i < n / 2; ++i) {
int a = nums[i], b = nums[n - 1 - i];
int low = 1 + min(a, b);
int high = limit + max(a, b);
int s = a + b;
diff[2] += 2;
diff[low] -= 1;
diff[s] -= 1;
diff[s + 1] += 1;
diff[high + 1] += 1;
}
int res = INT_MAX, curr = 0;
for (int S = 2; S <= 2 * limit; ++S) {
curr += diff[S];
res = min(res, curr);
}
return res;
}
};
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 < n / 2; ++i) {
int a = nums[i], b = nums[n - 1 - i];
int low = 1 + Math.min(a, b);
int high = limit + Math.max(a, b);
int s = a + b;
diff[2] += 2;
diff[low] -= 1;
diff[s] -= 1;
diff[s + 1] += 1;
diff[high + 1] += 1;
}
int res = Integer.MAX_VALUE, curr = 0;
for (int S = 2; S <= 2 * limit; ++S) {
curr += diff[S];
res = Math.min(res, curr);
}
return res;
}
}
var minMoves = function(nums, limit) {
const n = nums.length;
const diff = new Array(2 * limit + 2).fill(0);
for (let i = 0; i < n / 2; ++i) {
const a = nums[i], b = nums[n - 1 - i];
const low = 1 + Math.min(a, b);
const high = limit + Math.max(a, b);
const s = a + b;
diff[2] += 2;
diff[low] -= 1;
diff[s] -= 1;
diff[s + 1] += 1;
diff[high + 1] += 1;
}
let res = Number.MAX_SAFE_INTEGER, curr = 0;
for (let S = 2; S <= 2 * limit; ++S) {
curr += diff[S];
res = Math.min(res, curr);
}
return res;
};