Minimum Cost to Make Arrays Identical
MedPrompt
You are given two integer arrays arr and brr of length n, and an integer k. You can perform the following operations on arr any number of times:
- Split
arrinto any number of contiguous subarrays and rearrange these subarrays in any order. This operation has a fixed cost ofk. -
Choose any element in
arrand add or subtract a positive integerxto it. The cost of this operation isx.
Return the minimum total cost to make arr equal to brr.
Example 1:
Input: arr = [-7,9,5], brr = [7,-2,-5], k = 2
Output: 13
Explanation:
- Split
arrinto two contiguous subarrays:[-7]and[9, 5]and rearrange them as[9, 5, -7], with a cost of 2. - Subtract 2 from element
arr[0]. The array becomes[7, 5, -7]. The cost of this operation is 2. - Subtract 7 from element
arr[1]. The array becomes[7, -2, -7]. The cost of this operation is 7. - Add 2 to element
arr[2]. The array becomes[7, -2, -5]. The cost of this operation is 2.
The total cost to make the arrays equal is 2 + 2 + 7 + 2 = 13.
Example 2:
Input: arr = [2,1], brr = [2,1], k = 0
Output: 0
Explanation:
Since the arrays are already equal, no operations are needed, and the total cost is 0.
Constraints:
1 <= arr.length == brr.length <= 1050 <= k <= 2 * 1010-105 <= arr[i] <= 105-105 <= brr[i] <= 105
Approaches
2 approaches with complexity analysis and trade-offs.
A brute-force approach can be formulated using dynamic programming. The idea is to build a solution for the whole array by solving it for prefixes. We can define dp[i] as the minimum cost to make the first i elements of arr equal to the first i elements of brr. To compute dp[i], we consider all possible ways the last contiguous block arr[j...i-1] is formed and matched with brr[j...i-1]. This involves calculating the cost for this segment (either with or without rearrangement) and adding it to the optimal cost for the prefix arr[0...j-1]. This approach systematically explores all partitions of the array into blocks.
Algorithm
- Define a DP state
dp[i]as the minimum cost to make the prefixarr[0...i-1]identical tobrr[0...i-1]. - To compute
dp[i], we iterate through all possible split pointsjfrom0toi-1. The segment[j, i-1]is treated as the last block. - For each segment
arr[j...i-1], we calculate the cost to make it identical tobrr[j...i-1]. This cost itself has two possibilities: a. No rearrangement for this block: The cost is the sum of absolute differences:sum_{t=j}^{i-1} |arr[t] - brr[t]|. b. Rearrangement for this block: The cost involves the rearrangement penaltykplus the minimum modification cost. The minimum modification cost for two arrays of numbers where one can be permuted is obtained by sorting both and summing the absolute differences:k + sum(|sorted(arr[j...i-1])[t] - sorted(brr[j...i-1])[t]|). - The DP transition would look something like
dp[i] = min_{0 <= j < i} (dp[j] + cost_for_segment(j, i-1)). However, this is flawed because the costkis paid only once for the entire array, not per block. A more complex DP state is needed, likedp[i][0](cost for prefixiwithout using rearrangement) anddp[i][1](cost for prefixihaving used rearrangement), leading to a more complex set of transitions. - The base case would be
dp[0] = 0. - The final answer would be
dp[n](ormin(dp[n][0], dp[n][1])for the more complex state).
Walkthrough
This approach attempts to solve the problem by breaking it down into subproblems concerning prefixes of the arrays. Let's define dp[i] as the minimum cost to make arr[0...i-1] equal to brr[0...i-1]. The transition to compute dp[i] would involve considering all possible split points j < i, where arr[j...i-1] forms the last block in the prefix of length i.
The cost for this last block, cost(j, i), is the minimum of two scenarios:
- Matching
arr[j...i-1]tobrr[j...i-1]without rearrangement:sum_{t=j}^{i-1} |arr[t] - brr[t]|. - Matching
arr[j...i-1]tobrr[j...i-1]with rearrangement:k + sum(|sorted(arr[j...i-1])[t] - sorted(brr[j...i-1])[t]|).
The DP recurrence would be dp[i] = min_{0 <= j < i} (dp[j] + cost(j, i)). However, a major flaw in this simple DP is that the rearrangement cost k is global. A correct DP would need to track whether the rearrangement operation has been used, for instance, with a state dp[i][state], making the logic more convoluted and the computation even slower.
For example, a valid (but slow) DP could be:
dp[i][0] = min cost for prefix i without using rearrangement.
dp[i][1] = min cost for prefix i after using rearrangement.
dp[i][0] = dp[i-1][0] + |arr[i-1] - brr[i-1]|
dp[i][1] = min(dp[i-1][1] + cost_rearranged_for_one_element, dp[0][0] + k + cost_rearranged_for_prefix_i)O(N^3 log N) DP:
// This is a conceptual illustration of a slow DP and not a complete, correct solution.// A correct DP is significantly more complex to formulate.long[] dp = new long[n + 1];Arrays.fill(dp, Long.MAX_VALUE);dp[0] = 0;for (int i = 1; i <= n; i++) { for (int j = 0; j < i; j++) { // Cost for segment arr[j..i-1] and brr[j..i-1] long noRearrangeCost = 0; for (int l = j; l < i; l++) { noRearrangeCost += Math.abs(arr[l] - brr[l]); } int[] subArr = Arrays.copyOfRange(arr, j, i); int[] subBrr = Arrays.copyOfRange(brr, j, i); Arrays.sort(subArr); Arrays.sort(subBrr); long rearrangeModCost = 0; for (int l = 0; l < subArr.length; l++) { rearrangeModCost += Math.abs(subArr[l] - subBrr[l]); } // This DP logic is flawed as k is paid once. // A correct version would be much more complex. // dp[i] = Math.min(dp[i], dp[j] + noRearrangeCost); // dp[i] = Math.min(dp[i], dp[j] + k + rearrangeModCost); }}Complexity
Time
O(N^2 * N log N) or O(N^3) depending on the specific DP formulation. This is because for each state `dp[i]`, we iterate through `j`, and for each segment `[j, i-1]`, we might need to sort, which takes `O((i-j)log(i-j))` time.
Space
O(N) or O(N^2) depending on the DP state.
Trade-offs
Pros
It's a systematic way to explore the problem space, breaking it down into smaller subproblems.
Cons
The time complexity is very high, making it impractical for the given constraints.
The DP formulation is complex and easy to get wrong, especially in handling the one-time cost
k.
Solutions
Solution
class Solution {public long minCost(int[] arr, int[] brr, long k) { long c1 = calc(arr, brr); Arrays.sort(arr); Arrays.sort(brr); long c2 = calc(arr, brr) + k; return Math.min(c1, c2); }private long calc(int[] arr, int[] brr) { long ans = 0; for (int i = 0; i < arr.length; ++i) { ans += Math.abs(arr[i] - brr[i]); } return ans; }}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.