Minimum Absolute Sum Difference
MedPrompt
You are given two positive integer arrays nums1 and nums2, both of length n.
The absolute sum difference of arrays nums1 and nums2 is defined as the sum of |nums1[i] - nums2[i]| for each 0 <= i < n (0-indexed).
You can replace at most one element of nums1 with any other element in nums1 to minimize the absolute sum difference.
Return the minimum absolute sum difference after replacing at most one element in the array nums1. Since the answer may be large, return it modulo 109 + 7.
|x| is defined as:
xifx >= 0, or-xifx < 0.
Example 1:
|1-2| + (|1-3| or |5-3|) + |5-5| = Example 2:
Input: nums1 = [2,4,6,8,10], nums2 = [2,4,6,8,10]
Output: 0
Explanation: nums1 is equal to nums2 so no replacement is needed. This will result in an
absolute sum difference of 0.Example 3:
|10-9| + |10-3| + |4-5| + |4-1| + |2-7| + |7-4| = 20
Constraints:
n == nums1.lengthn == nums2.length1 <= n <= 1051 <= nums1[i], nums2[i] <= 105
Approaches
2 approaches with complexity analysis and trade-offs.
This approach involves a straightforward, exhaustive search. For each element in nums1, we consider replacing it with every other element from nums1 (including itself). We calculate the total absolute sum difference for each possible single replacement and find the minimum among them. This method guarantees finding the optimal solution but is computationally expensive.
Algorithm
- Calculate the initial sum
S = sum(|nums1[i] - nums2[i]|). - Initialize
maxReduction = 0. - Use a nested loop. The outer loop iterates through each index
iofnums1(the element to be replaced). - The inner loop iterates through each index
jofnums1(the replacement element). - Inside the inner loop, calculate the potential reduction:
reduction = |nums1[i] - nums2[i]| - |nums1[j] - nums2[i]|. - Update
maxReduction = max(maxReduction, reduction). - The final minimum sum is
S - maxReduction. - Return the result modulo
10^9 + 7.
Walkthrough
The algorithm begins by calculating the initial absolute sum difference, S = sum(|nums1[i] - nums2[i]|). The goal is to find the single replacement that provides the maximum possible reduction to this sum. We iterate through every element nums1[i] as a candidate to be replaced. For each nums1[i], we then iterate through every element nums1[j] as a potential new value. For each such potential replacement, we calculate the change in the difference at index i, which is |nums1[j] - nums2[i]| - |nums1[i] - nums2[i]|. We are interested in the most negative change, which corresponds to the maximum reduction. We keep track of the maxReduction found across all possibilities. The final answer is the initialSum - maxReduction. All sum calculations are performed using long to prevent overflow, and the final result is returned modulo 10^9 + 7.
class Solution { public int minAbsoluteSumDiff(int[] nums1, int[] nums2) { int n = nums1.length; long initialSum = 0; int MOD = 1_000_000_007; for (int i = 0; i < n; i++) { initialSum += Math.abs(nums1[i] - nums2[i]); } if (initialSum == 0) { return 0; } long maxReduction = 0; for (int i = 0; i < n; i++) { int originalDiff = Math.abs(nums1[i] - nums2[i]); // Try replacing nums1[i] with every element from nums1 for (int j = 0; j < n; j++) { int newDiff = Math.abs(nums1[j] - nums2[i]); long currentReduction = originalDiff - newDiff; if (currentReduction > maxReduction) { maxReduction = currentReduction; } } } long result = (initialSum - maxReduction) % MOD; return (int) result; }}Complexity
Time
O(n^2), where n is the length of the arrays. The nested loops dominate the runtime, iterating n*n times.
Space
O(1), as we only use a constant amount of extra space for variables.
Trade-offs
Pros
Conceptually simple and easy to implement.
Directly follows the problem definition.
Cons
Highly inefficient due to its quadratic time complexity.
Will not pass for large inputs, leading to a Time Limit Exceeded (TLE) error.
This approach optimizes the process of finding the best replacement. Instead of a linear scan for each element, we first sort a copy of nums1. Then, for each element nums2[i], we can use binary search on the sorted array to efficiently find the value in nums1 that is closest to nums2[i]. This reduces the time to find the best replacement from O(n) to O(log n), making the overall algorithm much faster.
Algorithm
- Create a sorted copy of
nums1, let's call itsortedNums1. - Calculate the initial sum
S = sum(|nums1[i] - nums2[i]|). - Initialize
maxReduction = 0. - For each index
ifrom0ton-1:- Find the element in
sortedNums1closest tonums2[i]using binary search. This involves checking the elements at the floor and ceiling ofnums2[i]'s position insortedNums1. - Let this minimum possible difference be
minNewDiff. - Calculate the potential reduction:
reduction = |nums1[i] - nums2[i]| - minNewDiff. - Update
maxReduction = max(maxReduction, reduction).
- Find the element in
- The final minimum sum is
S - maxReduction. - Return the result modulo
10^9 + 7.
Walkthrough
The strategy is to maximize the reduction |nums1[i] - nums2[i]| - |replacement - nums2[i]| for some index i. This is equivalent to finding a replacement from nums1 that minimizes |replacement - nums2[i]|. To do this efficiently, we first create a sorted copy of nums1. After calculating the initial total sum difference, we iterate through the original arrays. For each index i, we take nums2[i] as a target and use binary search on the sorted nums1 to find the element(s) closest to it. The closest elements will be the floor and/or ceiling of nums2[i] in the sorted array. By comparing nums2[i] with these two candidates, we can find the minimum possible new difference minNewDiff. The potential reduction for this index is then |nums1[i] - nums2[i]| - minNewDiff. We track the maximum such reduction over all i. The final answer is the initial sum minus this maximum reduction, modulo 10^9 + 7.
import java.util.Arrays; class Solution { public int minAbsoluteSumDiff(int[] nums1, int[] nums2) { int n = nums1.length; int MOD = 1_000_000_007; int[] sortedNums1 = nums1.clone(); Arrays.sort(sortedNums1); long initialSum = 0; for (int i = 0; i < n; i++) { initialSum += Math.abs(nums1[i] - nums2[i]); } if (initialSum == 0) { return 0; } long maxReduction = 0; for (int i = 0; i < n; i++) { int originalDiff = Math.abs(nums1[i] - nums2[i]); int target = nums2[i]; // Binary search to find the closest element in sortedNums1 int j = Arrays.binarySearch(sortedNums1, target); if (j < 0) { j = -(j + 1); // This is the insertion point } int minNewDiff = Integer.MAX_VALUE; // Candidate 1: element at or after insertion point (ceiling) if (j < n) { minNewDiff = Math.min(minNewDiff, Math.abs(sortedNums1[j] - target)); } // Candidate 2: element before insertion point (floor) if (j > 0) { minNewDiff = Math.min(minNewDiff, Math.abs(sortedNums1[j - 1] - target)); } long currentReduction = originalDiff - minNewDiff; if (currentReduction > maxReduction) { maxReduction = currentReduction; } } long result = initialSum - maxReduction; return (int) (result % MOD); }}Complexity
Time
O(n log n). Sorting the array takes O(n log n). The main loop runs n times, with each iteration performing a binary search that takes O(log n), resulting in another O(n log n) complexity. Thus, the total time is O(n log n).
Space
O(n), for storing the sorted copy of `nums1`. If modifying the input array `nums1` were allowed, this could be reduced to O(log n) or O(1) depending on the sorting algorithm's space complexity.
Trade-offs
Pros
Efficient, with a time complexity of O(n log n), which is suitable for the given constraints.
Correctly finds the optimal solution.
Cons
Requires O(n) extra space to store the sorted copy of the array.
Slightly more complex to implement than the brute-force approach due to the binary search logic.
Solutions
Solution
class Solution {public int minAbsoluteSumDiff(int[] nums1, int[] nums2) { final int mod = (int)1 e9 + 7; int[] nums = nums1.clone(); Arrays.sort(nums); int s = 0, n = nums.length; for (int i = 0; i < n; ++i) { s = (s + Math.abs(nums1[i] - nums2[i])) % mod; } int mx = 0; for (int i = 0; i < n; ++i) { int d1 = Math.abs(nums1[i] - nums2[i]); int d2 = 1 << 30; int j = search(nums, nums2[i]); if (j < n) { d2 = Math.min(d2, Math.abs(nums[j] - nums2[i])); } if (j > 0) { d2 = Math.min(d2, Math.abs(nums[j - 1] - nums2[i])); } mx = Math.max(mx, d1 - d2); } return (s - mx + mod) % mod; }private int search(int[] nums, int x) { int left = 0, right = nums.length; while (left < right) { int mid = (left + right) >>> 1; if (nums[mid] >= x) { right = mid; } else { left = mid + 1; } } return left; }}/** * @param {number[]} nums1 * @param {number[]} nums2 * @return {number} */ var minAbsoluteSumDiff = function (nums1, nums2) { const mod = 10 ** 9 + 7; const nums = [...nums1]; nums.sort((a, b) => a - b); const n = nums.length; let s = 0; for (let i = 0; i < n; ++i) { s = (s + Math.abs(nums1[i] - nums2[i])) % mod; } let mx = 0; for (let i = 0; i < n; ++i) { const d1 = Math.abs(nums1[i] - nums2[i]); let d2 = 1 << 30; let j = search(nums, nums2[i]); if (j < n) { d2 = Math.min(d2, Math.abs(nums[j] - nums2[i])); } if (j) { d2 = Math.min(d2, Math.abs(nums[j - 1] - nums2[i])); } mx = Math.max(mx, d1 - d2); } return (s - mx + mod) % mod; };function search(nums, x) { let left = 0; let right = nums.length; while (left < right) { const mid = (left + right) >> 1; if (nums[mid] >= x) { right = mid; } else { left = mid + 1; } } return left;}class Solution {public: int minAbsoluteSumDiff(vector<int> &nums1, vector<int> &nums2) { const int mod = 1e9 + 7; vector<int> nums(nums1); sort(nums.begin(), nums.end()); int s = 0, n = nums.size(); for (int i = 0; i < n; ++i) { s = (s + abs(nums1[i] - nums2[i])) % mod; } int mx = 0; for (int i = 0; i < n; ++i) { int d1 = abs(nums1[i] - nums2[i]); int d2 = 1 << 30; int j = lower_bound(nums.begin(), nums.end(), nums2[i]) - nums.begin(); if (j < n) { d2 = min(d2, abs(nums[j] - nums2[i])); } if (j) { d2 = min(d2, abs(nums[j - 1] - nums2[i])); } mx = max(mx, d1 - d2); } return (s - mx + mod) % mod; }};class Solution: def minAbsoluteSumDiff(self, nums1: List[int], nums2: List[int]) -> int: mod = 10 ** 9 + 7 nums = sorted(nums1) s = sum(abs(a - b) for a, b in zip(nums1, nums2)) % mod mx = 0 for a, b in zip(nums1, nums2): d1, d2 = abs(a - b), inf i = bisect_left(nums, b) if i < len(nums): d2 = min(d2, abs(nums[i] - b)) if i: d2 = min(d2, abs(nums[i - 1] - b)) mx = max(mx, d1 - d2) return (s - mx + mod) % modVideo 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.