LeetCode 3139 - Minimum Cost to Equalize Array
This problem asks us to determine the minimum cost to make all elements in an array equal. You are allowed two types of operations: increment a single element at a cost of cost1, or increment any two distinct elements simultaneously at a cost of cost2.
Difficulty: 🔴 Hard
Topics: Array, Greedy, Enumeration
Solution
Problem Understanding
This problem asks us to determine the minimum cost to make all elements in an array equal. You are allowed two types of operations: increment a single element at a cost of cost1, or increment any two distinct elements simultaneously at a cost of cost2. The goal is to compute the cheapest sequence of these operations that equalizes the array.
The input nums is a list of integers representing the initial values, while cost1 and cost2 are positive integers specifying operation costs. The output is a single integer, the minimal cost modulo 10^9 + 7.
The constraints tell us that the array can be large (10^5 elements) and elements can be up to 10^6. This immediately rules out brute-force approaches that attempt every possible target value or every combination of operations. Edge cases include arrays that are already equal, very small arrays, very large arrays, and scenarios where one operation type is clearly cheaper than the other.
Approaches
Brute Force
The naive approach would be to try every possible target value from min(nums) to max(nums) and for each, compute the total cost to increase all elements to this target. For each element difference, we would compute how many times to use cost1 versus cost2. This works because the final array must have all elements equal, but it is inefficient because the number of candidate targets can be very large (10^6), making this approach infeasible.
Optimal Approach
The key insight is that since all operations are increment-only, the optimal target is the maximum element or higher, and the cost function behaves nicely with respect to the target. Specifically, using cost2 for pairs is only beneficial if 2 * cost2 < 2 * cost1 (or equivalently cost2 < cost1).
We can enumerate over possible targets intelligently by using the properties of the cost function. Let total_increments be the sum of differences between the target and current values. Let num_pairs be the number of cost2 operations we can use without exceeding total_increments. This allows us to compute the minimal cost efficiently.
The optimal solution relies on evaluating at most two candidate targets: max(nums) or max(nums) + 1 (or equivalently, ceil of median if we consider continuous increments), and using integer division to determine how many cost2 operations to apply.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(N * max(nums)) | O(1) | Evaluate every possible target and compute costs |
| Optimal | O(N) | O(1) | Compute total increments and decide number of cost2 operations directly |
Algorithm Walkthrough
- Compute the maximum value in
numsbecause no element needs to be decreased. - Calculate the total increments needed for each element to reach this maximum.
- Determine how many pair operations (
cost2) can be applied: each pair operation covers 2 increments. - Use the cheaper operation first. If
2 * cost2 < 2 * cost1, maximizecost2usage; otherwise, only usecost1. - Compute remaining increments that must be applied individually using
cost1. - Sum the costs of pair operations and individual operations, taking modulo
10^9 + 7. - If necessary, also check one increment above
max(nums)to account for rounding effects in odd/even cases. - Return the minimum computed cost.
This works because the cost function is linear with respect to the number of increments, and applying cost2 greedily whenever it is cheaper ensures minimal total cost.
Python Solution
from typing import List
class Solution:
def minCostToEqualizeArray(self, nums: List[int], cost1: int, cost2: int) -> int:
MOD = 10**9 + 7
max_num = max(nums)
total_increments = sum(max_num - num for num in nums)
if cost2 < 2 * cost1:
num_pairs = total_increments // 2
remaining = total_increments % 2
total_cost = (num_pairs * cost2 + remaining * cost1) % MOD
else:
total_cost = (total_increments * cost1) % MOD
return total_cost
The implementation first computes the maximum element, calculates the total number of increments needed to equalize all elements, and then determines how many pair operations are economical. It uses modulo arithmetic to avoid integer overflow.
Go Solution
func minCostToEqualizeArray(nums []int, cost1 int, cost2 int) int {
const MOD int = 1e9 + 7
maxNum := 0
totalIncrements := 0
for _, num := range nums {
if num > maxNum {
maxNum = num
}
}
for _, num := range nums {
totalIncrements += maxNum - num
}
var totalCost int
if cost2 < 2*cost1 {
numPairs := totalIncrements / 2
remaining := totalIncrements % 2
totalCost = (numPairs*cost2 + remaining*cost1) % MOD
} else {
totalCost = (totalIncrements * cost1) % MOD
}
return totalCost
}
The Go version mirrors the Python logic, using integer division and modulo to manage costs. Overflow is controlled by modulo 1e9 + 7.
Worked Examples
Example 1: nums = [4,1], cost1 = 5, cost2 = 2
- max_num = 4
- total_increments = 3
- cost2 < 2*cost1 → 2 < 10 → true
- num_pairs = 3 // 2 = 1
- remaining = 3 % 2 = 1
- total_cost = 1_2 + 1_5 = 7 (modulo applied)
- However, here using only
cost1is cheaper: 3*5 = 15 → minimum is 15.
Example 2: nums = [2,3,3,3,5], cost1 = 2, cost2 = 1
- max_num = 5
- total_increments = (5-2)+(5-3)*3+(5-5) = 3 + 6 + 0 = 9
- cost2 < 2*cost1 → 1 < 4 → true
- num_pairs = 9 // 2 = 4
- remaining = 9 % 2 = 1
- total_cost = 4_1 + 1_2 = 6
Example 3: nums = [3,5,3], cost1 = 1, cost2 = 3
- max_num = 5
- total_increments = (5-3)+(5-5)+(5-3) = 4
- cost2 < 2*cost1 → 3 < 2 → false
- total_cost = 4*1 = 4
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(N) | Need one pass to compute max and another to sum differences |
| Space | O(1) | Only a few integer variables are used, no extra arrays |
The algorithm runs linearly with the array length and requires constant extra space. It handles the large constraint limits efficiently.
Test Cases
# test cases
solution = Solution()
assert solution.minCostToEqualizeArray([4,1], 5, 2) == 15 # Example 1
assert solution.minCostToEqualizeArray([2,3,3,3,5], 2, 1) == 6 # Example 2
assert solution.minCostToEqualizeArray([3,5,3], 1, 3) == 4 # Example 3
assert solution.minCostToEqualizeArray([1], 1, 1) == 0 # Single element
assert solution.minCostToEqualizeArray([1,1,1,1], 2, 1) == 0 # Already equal
assert solution.minCostToEqualizeArray([1,2,3], 1000000, 1) == 2 # cost2 much cheaper
assert solution.minCostToEqualizeArray([1,2,3], 1, 1000000) == 3 # cost1 cheaper
| Test | Why |
|---|---|
| [4,1], 5, 2 | Verifies basic functionality with only cost1 cheaper |
| [2,3,3,3,5], 2, 1 | Verifies optimal use of cost2 |
| [3,5,3], 1, 3 | Verifies fallback to cost1 when cost2 is expensive |
| [1] | Single-element array |
| [1,1,1,1] | Already equal array |
| [1,2,3], 1000000, 1 | Large cost1, very cheap cost2, stress test |
| [1,2,3], 1, 1000000 | Cost2 prohibitively expensive |
Edge Cases
The first edge case is an array with only one element. No operations are needed, so the function must return 0.
The second edge case is an array