Minimum Array Changes to Make Differences Equal
MedPrompt
You are given an integer array nums of size n where n is even, and an integer k.
You can perform some changes on the array, where in one change you can replace any element in the array with any integer in the range from 0 to k.
You need to perform some changes (possibly none) such that the final array satisfies the following condition:
- There exists an integer
Xsuch thatabs(a[i] - a[n - i - 1]) = Xfor all(0 <= i < n).
Return the minimum number of changes required to satisfy the above condition.
Example 1:
Input: nums = [1,0,1,2,4,3], k = 4
Output: 2
Explanation:
We can perform the following changes:
- Replace
nums[1]by 2. The resulting array isnums = [1,2,1,2,4,3]. - Replace
nums[3]by 3. The resulting array isnums = [1,2,1,3,4,3].
The integer X will be 2.
Example 2:
Input: nums = [0,1,2,3,3,6,5,4], k = 6
Output: 2
Explanation:
We can perform the following operations:
- Replace
nums[3]by 0. The resulting array isnums = [0,1,2,0,3,6,5,4]. - Replace
nums[4]by 4. The resulting array isnums = [0,1,2,0,4,6,5,4].
The integer X will be 4.
Constraints:
2 <= n == nums.length <= 105nis even.0 <= nums[i] <= k <= 105
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly translates the problem statement into a solution. We test every possible value for the final difference X, which can range from 0 to k. For each potential X, we calculate the total number of modifications needed across all n/2 pairs of elements (nums[i], nums[n-1-i]). The minimum of these totals over all X is our answer.
Algorithm
- Initialize
min_changesto a very large number (e.g.,n). - Iterate through each possible target difference
Xfrom0tok. - For each
X, calculate the total changes required:- Initialize
current_changesto0. - Iterate through each pair of elements
(a, b) = (nums[i], nums[n - 1 - i])forifrom0ton/2 - 1. - Determine the cost for the current pair to achieve the difference
X:- If
abs(a - b) == X, the cost is0(no changes needed). - Otherwise, check if one change is sufficient. This is possible if
Xis within the range of differences achievable by changing one element. The maximum achievable difference with one change ismax_diff = max(a, b, k - a, k - b). IfX <= max_diff, the cost is1. - Otherwise, two changes are required, so the cost is
2.
- If
- Add the pair's cost to
current_changes.
- Initialize
- After iterating through all pairs, update
min_changes = min(min_changes, current_changes). - After checking all possible
X,min_changeswill hold the minimum number of changes required.
Walkthrough
For each pair of elements (a, b) and a target difference X, we need to find the minimum changes to make abs(a' - b') = X, where a' and b' are the new values in the range [0, k]. The cost is determined as follows:
- 0 changes: If the original difference
abs(a - b)is already equal toX. - 1 change: If
abs(a - b) != X, but we can change eitheraorbto satisfy the condition. By changing one element (sayatoa'), the range of achievable differences is[0, max(b, k-b)]. Considering changes to bothaandb, the maximum difference we can achieve with one change ismax(a, b, k-a, k-b). IfXis less than or equal to this maximum, one change is sufficient. - 2 changes: If both 0 and 1 change are not possible, we can always achieve the difference
Xwith two changes (e.g., by setting one element to0and the other toX, both of which are valid values in[0, k]).
The algorithm iterates through all X from 0 to k, computes the total cost for each X by summing up the costs for all n/2 pairs, and returns the minimum total cost found.
class Solution { public int minChanges(int[] nums, int k) { int n = nums.length; int minTotalChanges = n; // Maximum possible changes for (int X = 0; X <= k; X++) { int currentChanges = 0; for (int i = 0; i < n / 2; i++) { int a = nums[i]; int b = nums[n - 1 - i]; if (Math.abs(a - b) == X) { // 0 changes needed continue; } else { int maxDiffOneChange = Math.max(Math.max(a, k - a), Math.max(b, k - b)); if (X <= maxDiffOneChange) { // 1 change is sufficient currentChanges += 1; } else { // 2 changes are required currentChanges += 2; } } } minTotalChanges = Math.min(minTotalChanges, currentChanges); } return minTotalChanges; }}Complexity
Time
O(n * k). The outer loop runs `k+1` times, and the inner loop runs `n/2` times. This results in a total time complexity proportional to `n * k`.
Space
O(1) extra space.
Trade-offs
Pros
Simple to understand and implement.
Correctly solves the problem for smaller constraints.
Cons
The time complexity of
O(n * k)is too high for the given constraints (n, k <= 10^5), leading to a Time Limit Exceeded (TLE) error on most platforms.
The brute-force approach is inefficient because it repeatedly calculates costs. A more optimal method analyzes how the cost for each pair contributes to the total cost across all possible differences X. We can observe that for a single pair, the number of changes required is either 0, 1, or 2, and this value only changes at specific thresholds of X. Instead of calculating the total cost for each X from scratch, we can calculate the contribution of each pair to all possible X values at once. This can be done efficiently using a difference array to handle the range updates corresponding to cost savings.
Algorithm
- The cost for any pair to achieve a difference
Xis2by default. This cost can be reduced. - If
Xcan be achieved with one change, the cost becomes1(a saving of 1). This is true forX <= max(a, b, k-a, k-b). - If
Xis the original difference, the cost becomes0(an additional saving of 1). - The total cost for a difference
Xis(n/2 * 2) - TotalSavings(X). To minimize cost, we must maximize savings. - We can calculate
TotalSavings(X)for allXsimultaneously using a difference array. - Steps:
- Initialize a difference array
deltaof sizek + 2to all zeros. - For each pair
(a, b): a. Calculated = abs(a - b)andm = max(a, b, k-a, k-b). b. A saving of 1 applies to allXin[0, m]. We register this range update in the difference array:delta[0]++anddelta[m + 1]--. c. An additional saving of 1 applies atX = d. We register this point update:delta[d]++anddelta[d + 1]--. - After processing all pairs, compute the prefix sum of
deltato get thesavingsarray.savings[X]will store the total savings for differenceX. - Find the maximum value
max_savingsin thesavingsarray. - The minimum number of changes is
n - max_savings(since each of then/2pairs requires 2 changes by default, for a total ofnchanges).
- Initialize a difference array
Walkthrough
Let's analyze the cost for a single pair (a, b). The default cost is 2 changes. We get 'savings' on this cost.
- We save 1 change if the target difference
Xcan be achieved with one modification. This is possible for anyXin the range[0, m], wherem = max(a, b, k-a, k-b). - We save an additional 1 change if the target
Xis equal to the pair's original differenced = abs(a-b).
So, for a given X, the total savings is the sum of savings from all pairs. TotalSavings(X) = sum_pairs(I(X <= m) + I(X == d)), where I is the indicator function. The total cost is n - TotalSavings(X). Our goal is to find max(TotalSavings(X)).
We can compute the TotalSavings array efficiently. For each pair, we have two updates:
- Add 1 to
TotalSavings[X]for allXin[0, m]. This is a range update. - Add 1 to
TotalSavings[X]forX = d. This is a point update.
A difference array (or prefix sum technique) is perfect for handling many range updates. We create a delta array. A range update [L, R] is done by delta[L]++ and delta[R+1]--. A point update at P is a range update [P, P]. After processing all pairs, we compute the prefix sum of delta to get the final TotalSavings array. The maximum value in this array gives us the maximum savings, which leads to the minimum changes.
class Solution { public int minChanges(int[] nums, int k) { int n = nums.length; int[] delta = new int[k + 2]; for (int i = 0; i < n / 2; i++) { int a = nums[i]; int b = nums[n - 1 - i]; // To simplify, let u <= v int u = Math.min(a, b); int v = Math.max(a, b); // Original difference int diff = v - u; // Max difference achievable with one change // max_diff = max(v, k-u) int maxDiffOneChange = Math.max(v, k - u); // Cost is 2 by default. // Savings of 1 for X in [0, maxDiffOneChange] // Additional saving of 1 for X = diff // Update for saving of 1 over range [0, maxDiffOneChange] delta[0] += 1; delta[maxDiffOneChange + 1] -= 1; // Update for additional saving of 1 at point diff delta[diff] += 1; delta[diff + 1] -= 1; } int maxSavings = 0; int currentSavings = 0; for (int x = 0; x <= k; x++) { currentSavings += delta[x]; maxSavings = Math.max(maxSavings, currentSavings); } // Total changes for n/2 pairs is n by default (2 per pair) return n - maxSavings; }}Complexity
Time
O(n + k). We iterate through `n/2` pairs once to populate the difference array, which takes `O(n)`. Then, we iterate through the difference array of size `k` to compute prefix sums and find the maximum, which takes `O(k)`.
Space
O(k) to store the difference array and the computed savings.
Trade-offs
Pros
Highly efficient with a linear time complexity.
Passes the given constraints with ease.
Cons
The logic is more complex than the brute-force approach, involving concepts like difference arrays and prefix sums.
Requires extra space proportional to
k.
Solutions
Solution
class Solution {public int minChanges(int[] nums, int k) { int[] d = new int[k + 2]; int n = nums.length; for (int i = 0; i < n / 2; ++i) { int x = Math.min(nums[i], nums[n - i - 1]); int y = Math.max(nums[i], nums[n - i - 1]); d[0] += 1; d[y - x] -= 1; d[y - x + 1] += 1; d[Math.max(y, k - x) + 1] -= 1; d[Math.max(y, k - x) + 1] += 2; } int ans = n, s = 0; for (int x : d) { s += x; ans = Math.min(ans, s); } return ans; }}class Solution {public: int minChanges(vector<int> &nums, int k) { int d[k + 2]; memset(d, 0, sizeof(d)); int n = nums.size(); for (int i = 0; i < n / 2; ++i) { int x = min(nums[i], nums[n - i - 1]); int y = max(nums[i], nums[n - i - 1]); d[0] += 1; d[y - x] -= 1; d[y - x + 1] += 1; d[max(y, k - x) + 1] -= 1; d[max(y, k - x) + 1] += 2; } int ans = n, s = 0; for (int x : d) { s += x; ans = min(ans, s); } return ans; }};class Solution: def minChanges(self, nums: List[int], k: int) -> int: d = [0] * (k + 2) n = len(nums) for i in range(n // 2): x, y = nums[i], nums[- i - 1] if x > y: x, y = y, x d[0] += 1 d[y - x] -= 1 d[y - x + 1] += 1 d[max(y, k - x) + 1] -= 1 d[max(y, k - x) + 1] += 2 return min(accumulate(d))Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.