Minimum Total Cost to Make Arrays Unequal
HardPrompt
You are given two 0-indexed integer arrays nums1 and nums2, of equal length n.
In one operation, you can swap the values of any two indices of nums1. The cost of this operation is the sum of the indices.
Find the minimum total cost of performing the given operation any number of times such that nums1[i] != nums2[i] for all 0 <= i <= n - 1 after performing all the operations.
Return the minimum total cost such that nums1 and nums2 satisfy the above condition. In case it is not possible, return -1.
Example 1:
Input: nums1 = [1,2,3,4,5], nums2 = [1,2,3,4,5]
Output: 10
Explanation:
One of the ways we can perform the operations is:
- Swap values at indices 0 and 3, incurring cost = 0 + 3 = 3. Now, nums1 = [4,2,3,1,5]
- Swap values at indices 1 and 2, incurring cost = 1 + 2 = 3. Now, nums1 = [4,3,2,1,5].
- Swap values at indices 0 and 4, incurring cost = 0 + 4 = 4. Now, nums1 =[5,3,2,1,4].
We can see that for each index i, nums1[i] != nums2[i]. The cost required here is 10.
Note that there are other ways to swap values, but it can be proven that it is not possible to obtain a cost less than 10.Example 2:
Input: nums1 = [2,2,2,1,3], nums2 = [1,2,2,3,3]
Output: 10
Explanation:
One of the ways we can perform the operations is:
- Swap values at indices 2 and 3, incurring cost = 2 + 3 = 5. Now, nums1 = [2,2,1,2,3].
- Swap values at indices 1 and 4, incurring cost = 1 + 4 = 5. Now, nums1 = [2,3,1,2,2].
The total cost needed here is 10, which is the minimum possible.Example 3:
Input: nums1 = [1,2,2], nums2 = [1,2,2]
Output: -1
Explanation:
It can be shown that it is not possible to satisfy the given conditions irrespective of the number of operations we perform.
Hence, we return -1.
Constraints:
n == nums1.length == nums2.length1 <= n <= 1051 <= nums1[i], nums2[i] <= n
Approaches
2 approaches with complexity analysis and trade-offs.
This approach attempts to solve the problem by exploring all possible ways to resolve the conflicts. It identifies all indices i where nums1[i] == nums2[i] and then uses a brute-force, recursive method to try all valid pairings for swaps, either between two conflicting indices or between a conflicting and a non-conflicting index. It calculates the cost for each complete set of swaps and finds the minimum among them.
Algorithm
- Identify the set of conflicting indices
S = {i | nums1[i] == nums2[i]}. - The problem is to resolve all conflicts in
S. Each conflictimust be resolved by swappingnums1[i]with somenums1[j]. - This approach explores all possible ways to pair up the conflicting indices for swaps.
- A recursive backtracking function, say
solve(conflicts_to_resolve), is defined. - In the function, pick a conflict
ifrom the set. - Try pairing
iwith every other conflictjin the set. For each pair(i, j): a. Check if swapping them is valid (i.e.,nums1[i] != nums2[j]andnums1[j] != nums2[i]). b. If valid, recursively callsolvefor the remaining conflicts, addingi+jto the cost. - Also, try pairing
iwith every non-conflicting indexk \notin S. a. Check if swapping them is valid (i.e.,nums1[k]resolves conflictiwithout creating a new one atk). b. If valid, recursively callsolvefor remaining conflicts, addingi+kto the cost. - The base case for the recursion is when there are no more conflicts to resolve, in which case the cost is 0.
- Keep track of the minimum cost found across all valid sequences of swaps.
Walkthrough
The fundamental observation is that for every index i where nums1[i] == nums2[i], the value nums1[i] must be changed. This can only be done by swapping it with another value nums1[j]. This brute-force approach systematically tries every possible way to resolve these conflicts.
We can model this as a search problem. Let S be the set of conflicting indices. We need to find a sequence of swaps that makes nums1[i] != nums2[i] for all i. A backtracking algorithm can explore the space of possible swaps. For each unresolved conflict, we can try to swap it with another unresolved conflict or with a non-conflicting index. We would explore all such possibilities, pruning branches that are invalid, and return the minimum cost found.
For instance, a recursive function could take the set of remaining conflicts as input. In each call, it would pick one conflict, try all valid swap partners for it, and recurse on the remaining set of conflicts. The number of ways to pair up conflicts can be very large, leading to a combinatorial explosion.
// This is a conceptual illustration. A full implementation would be very complex and inefficient.class Solution { public long minimumTotalCost(int[] nums1, int[] nums2) { // This approach is too slow and complex to implement fully for the given constraints. // It would involve a backtracking function like: // findMinCost(conflicts, currentCost) // where 'conflicts' is a list of indices to resolve. // In each step, you'd pick a conflict, try all valid swap partners, // and recurse, updating the cost. // The number of possibilities makes this approach infeasible. return -1; // Placeholder for an infeasible approach }}Complexity
Time
Exponential, likely O(S!) or worse, where S is the number of conflicts. This will time out for all but the smallest inputs.
Space
O(N) or O(S^2) where S is the number of conflicts, for storing the state and recursion stack.
Trade-offs
Pros
Guaranteed to find the optimal solution if it runs to completion.
Cons
Extremely inefficient due to its exponential time complexity.
Not feasible for the given constraints (
nup to 10^5).The logic for handling swaps with non-conflicting indices and ensuring no new conflicts are created adds significant complexity to the implementation.
This efficient approach uses a greedy strategy based on analyzing the values at the conflicting indices. It first calculates a base cost by summing all conflicting indices. Then, it identifies the most frequent value (v_dom) among these conflicts. The strategy is to resolve as many conflicts as possible by swapping non-dominant conflicts with dominant ones. Any remaining dominant conflicts must be swapped with non-conflicting indices. The algorithm greedily chooses the cheapest available non-conflicting indices for these swaps to minimize the total cost.
Algorithm
- First, identify all conflicting indices
iwherenums1[i] == nums2[i]. LetSbe the set of these indices. - Calculate the base cost, which is the sum of all indices in
S, since each must participate in at least one swap.total_cost = sum(i for i in S). - Count the frequency of each value
vat conflicting indices. Store this in a map or array,counts[v]. - Find the value
v_domthat appears most frequently among conflicts (the dominant value), and its frequencymax_freq. - The core idea is to pair up conflicts. A conflict of value
v1can be resolved by swapping with a conflict of valuev2ifv1 != v2. We can resolves - max_freqnon-dominant conflicts by pairing them withs - max_freqdominant conflicts. This leavesmax_freq - (s - max_freq) = 2*max_freq - sdominant conflicts unresolved. - Let
num_single = 2*max_freq - s. Ifnum_single <= 0, all conflicts can be resolved by swapping withinS, and the cost is simplytotal_cost. - If
num_single > 0, thesenum_singleconflicts (all of valuev_dom) must be resolved by swapping with indicesloutside ofS. - A valid external partner
lmust satisfy:l \notin S,nums1[l] != v_dom, andnums2[l] != v_dom. The first condition ensures we don't create a new conflict forl's original value, and the second ensures we don't create a newv_domconflict atl. - Collect all such valid partner indices
linto a list. - If the number of available partners is less than
num_single, it's impossible to resolve all conflicts. Return -1. - Otherwise, to minimize the added cost, greedily pick the
num_singlepartners with the smallest indices. Add the sum of these indices tototal_cost. - Return the final
total_cost.
Walkthrough
The key insight is that the total cost of swaps can be broken down. Any index i that is part of a swap (i, j) contributes i to the total cost. Since every conflicting index must be part of at least one swap, the sum of all conflicting indices is a baseline for the total cost.
The problem then becomes minimizing the sum of the indices of the swap partners.
We can resolve two conflicts i and j by swapping nums1[i] and nums1[j] if their values are different. This suggests a greedy strategy: find the value v_dom that is most common among all conflicts. Let its frequency be max_freq. The |S| - max_freq conflicts with other values can be paired up and swapped with |S| - max_freq conflicts of value v_dom. This resolves 2 * (|S| - max_freq) conflicts.
The cost for these internal swaps is already accounted for by summing up all indices in S.
We are left with max_freq - (|S| - max_freq) = 2*max_freq - |S| conflicts of value v_dom. These must be swapped with indices l from outside the conflict set S. To maintain validity, such an l must not have v_dom as its value in either nums1 or nums2. We find all such valid l's and, to minimize cost, pick the ones with the smallest indices. Their indices are added to our running total cost.
If at any point we don't have enough valid partners, the task is impossible.
import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map; class Solution { public long minimumTotalCost(int[] nums1, int[] nums2) { long totalCost = 0; int conflicts = 0; Map<Integer, Integer> counts = new HashMap<>(); int n = nums1.length; boolean[] isConflict = new boolean[n]; for (int i = 0; i < n; i++) { if (nums1[i] == nums2[i]) { conflicts++; totalCost += i; counts.put(nums1[i], counts.getOrDefault(nums1[i], 0) + 1); isConflict[i] = true; } } if (conflicts == 0) { return 0; } int maxFreq = 0; int dominantVal = -1; for (Map.Entry<Integer, Integer> entry : counts.entrySet()) { if (entry.getValue() > maxFreq) { maxFreq = entry.getValue(); dominantVal = entry.getKey(); } } int numToSwapExternally = 2 * maxFreq - conflicts; if (numToSwapExternally <= 0) { return totalCost; } List<Integer> partners = new ArrayList<>(); for (int i = 0; i < n; i++) { if (!isConflict[i] && nums1[i] != dominantVal && nums2[i] != dominantVal) { partners.add(i); } } if (partners.size() < numToSwapExternally) { return -1; } for (int i = 0; i < numToSwapExternally; i++) { totalCost += partners.get(i); } return totalCost; }}Complexity
Time
O(N) because we iterate through the arrays a constant number of times. The map operations take, on average, O(1) time. If we use arrays for frequency counts (since values are bounded by `n`), it's guaranteed O(N).
Space
O(N) to store the conflict status, frequency counts, and potential partner indices.
Trade-offs
Pros
Very efficient, with a linear or near-linear time complexity.
Correctly handles all cases, including impossible scenarios.
The greedy choice is proven to be optimal for this problem structure.
Cons
The logic can be subtle to reason about, particularly the calculation of remaining conflicts and the conditions for external swap partners.
Solutions
Solution
class Solution {public long minimumTotalCost(int[] nums1, int[] nums2) { long ans = 0; int same = 0; int n = nums1.length; int[] cnt = new int[n + 1]; for (int i = 0; i < n; ++i) { if (nums1[i] == nums2[i]) { ans += i; ++same; ++cnt[nums1[i]]; } } int m = 0, lead = 0; for (int i = 0; i < cnt.length; ++i) { int t = cnt[i] * 2 - same; if (t > 0) { m = t; lead = i; break; } } for (int i = 0; i < n; ++i) { if (m > 0 && nums1[i] != nums2[i] && nums1[i] != lead && nums2[i] != lead) { ans += i; --m; } } return m > 0 ? -1 : ans; }}class Solution {public: long long minimumTotalCost(vector<int> &nums1, vector<int> &nums2) { long long ans = 0; int same = 0; int n = nums1.size(); int cnt[n + 1]; memset(cnt, 0, sizeof cnt); for (int i = 0; i < n; ++i) { if (nums1[i] == nums2[i]) { ans += i; ++same; ++cnt[nums1[i]]; } } int m = 0, lead = 0; for (int i = 0; i < n + 1; ++i) { int t = cnt[i] * 2 - same; if (t > 0) { m = t; lead = i; break; } } for (int i = 0; i < n; ++i) { if (m > 0 && nums1[i] != nums2[i] && nums1[i] != lead && nums2[i] != lead) { ans += i; --m; } } return m > 0 ? -1 : ans; }};class Solution: def minimumTotalCost(self, nums1: List[int], nums2: List[int]) -> int: ans = same = 0 cnt = Counter() for i, (a, b) in enumerate(zip(nums1, nums2)): if a == b: same += 1 ans += i cnt[a] += 1 m = lead = 0 for k, v in cnt . items(): if v * 2 > same: m = v * 2 - same lead = k break for i, (a, b) in enumerate(zip(nums1, nums2)): if m and a != b and a != lead and b != lead: ans += i m -= 1 return - 1 if m else ansVideo 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.