3155. Maximum Number of Upgradable Servers 🔒
Problem Description
You have n
data centers, and each data center has servers that need to be upgraded. For each data center, you're given:
count[i]
: The number of servers in data centeri
upgrade[i]
: The cost to upgrade one server in data centeri
sell[i]
: The money you receive from selling one server in data centeri
money[i]
: The initial money available for data centeri
Your goal is to determine the maximum number of servers you can upgrade in each data center.
The key strategy is that you can sell some servers to get additional money, then use that money (plus your initial money) to upgrade the remaining servers. For example, if you have 10 servers and want to upgrade 6 of them, you could sell 4 servers to get extra funds, then use all your money to upgrade the remaining 6 servers.
Important constraints:
- Money from one data center cannot be transferred to another data center - each data center's budget is independent
- You can only upgrade servers that you haven't sold
- The maximum number of servers you can upgrade is limited by both the total number of servers and your available budget
Return an array answer
where answer[i]
represents the maximum number of servers that can be upgraded in data center i
.
The mathematical relationship is: if you want to upgrade x
servers out of count[i]
total servers, you can sell (count[i] - x)
servers to get (count[i] - x) × sell[i]
money. This money plus your initial money[i]
must be enough to cover the upgrade cost of x × upgrade[i]
.
Intuition
Let's think about what happens when we want to upgrade x
servers in a data center that has count[i]
total servers.
If we upgrade x
servers, we must sell (count[i] - x)
servers to maximize our budget. The money we get from selling these servers is (count[i] - x) × sell[i]
. Combined with our initial money money[i]
, our total budget becomes:
Total Budget = money[i] + (count[i] - x) × sell[i]
This budget must be enough to upgrade x
servers, which costs x × upgrade[i]
. So we need:
x × upgrade[i] ≤ money[i] + (count[i] - x) × sell[i]
Let's rearrange this inequality to solve for x
:
x × upgrade[i] ≤ money[i] + count[i] × sell[i] - x × sell[i]
x × upgrade[i] + x × sell[i] ≤ money[i] + count[i] × sell[i]
x × (upgrade[i] + sell[i]) ≤ money[i] + count[i] × sell[i]
x ≤ (money[i] + count[i] × sell[i]) / (upgrade[i] + sell[i])
This gives us the maximum number of servers we can afford to upgrade based on our budget constraints.
However, there's another constraint: we can't upgrade more servers than we actually have. So x ≤ count[i]
.
Therefore, the maximum number of servers we can upgrade is:
min(count[i], (money[i] + count[i] × sell[i]) / (upgrade[i] + sell[i]))
Since we need an integer result (we can't upgrade a fraction of a server), we use integer division:
min(count[i], (money[i] + count[i] × sell[i]) // (upgrade[i] + sell[i]))
Learn more about Math and Binary Search patterns.
Solution Approach
The solution uses a straightforward mathematical approach to calculate the maximum upgradable servers for each data center independently.
For each data center i
, we need to find the maximum value of x
(number of servers to upgrade) such that:
- We have enough money to upgrade
x
servers after selling(count[i] - x)
servers - We don't exceed the total number of servers available
The mathematical formula derived from our intuition is:
x ≤ (count[i] × sell[i] + money[i]) / (upgrade[i] + sell[i])
The implementation iterates through all data centers using Python's zip
function to process the corresponding elements from all four input arrays simultaneously:
for cnt, cost, income, cash in zip(count, upgrade, sell, money):
For each data center, we calculate:
-
The budget-constrained maximum:
(cnt * income + cash) // (cost + income)
cnt * income
represents the money we'd get if we sold all servers- Adding
cash
gives us the total available money - Dividing by
(cost + income)
gives us the maximum servers we can upgrade - Integer division
//
ensures we get a whole number
-
The physical constraint:
cnt
(we can't upgrade more servers than we have) -
Take the minimum of these two values:
min(cnt, (cnt * income + cash) // (cost + income))
The result for each data center is appended to the answer array, which is returned at the end.
This approach has a time complexity of O(n)
where n
is the number of data centers, and space complexity of O(n)
for storing the answer array.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example with 2 data centers:
count = [4, 3]
(servers in each data center)upgrade = [3, 5]
(cost to upgrade one server)sell = [4, 2]
(money from selling one server)money = [8, 9]
(initial budget)
Data Center 0 (index 0):
- We have 4 servers total
- Let's determine how many servers we can upgrade
Using our formula: min(count[0], (money[0] + count[0] × sell[0]) // (upgrade[0] + sell[0]))
Calculate the budget-based maximum:
- Total potential money =
money[0] + count[0] × sell[0] = 8 + 4 × 4 = 8 + 16 = 24
- Cost per server (upgrade + opportunity cost of not selling) =
upgrade[0] + sell[0] = 3 + 4 = 7
- Maximum affordable upgrades =
24 // 7 = 3
Physical constraint: count[0] = 4
Result: min(4, 3) = 3
servers can be upgraded
Let's verify: If we upgrade 3 servers, we sell 1 server:
- Money from selling:
1 × 4 = 4
- Total budget:
8 + 4 = 12
- Cost to upgrade 3 servers:
3 × 3 = 9
- Since 12 ≥ 9, we can indeed upgrade 3 servers ✓
Data Center 1 (index 1):
- We have 3 servers total
Calculate the budget-based maximum:
- Total potential money =
money[1] + count[1] × sell[1] = 9 + 3 × 2 = 9 + 6 = 15
- Cost per server =
upgrade[1] + sell[1] = 5 + 2 = 7
- Maximum affordable upgrades =
15 // 7 = 2
Physical constraint: count[1] = 3
Result: min(3, 2) = 2
servers can be upgraded
Let's verify: If we upgrade 2 servers, we sell 1 server:
- Money from selling:
1 × 2 = 2
- Total budget:
9 + 2 = 11
- Cost to upgrade 2 servers:
2 × 5 = 10
- Since 11 ≥ 10, we can upgrade 2 servers ✓
Final Answer: [3, 2]
Solution Implementation
1from typing import List
2
3
4class Solution:
5 def maxUpgrades(
6 self, count: List[int], upgrade: List[int], sell: List[int], money: List[int]
7 ) -> List[int]:
8 """
9 Calculate the maximum number of items that can be upgraded for each test case.
10
11 Args:
12 count: List of initial item counts
13 upgrade: List of upgrade costs per item
14 sell: List of selling prices per item
15 money: List of initial money amounts
16
17 Returns:
18 List of maximum upgradeable items for each test case
19 """
20 result = []
21
22 # Process each test case
23 for item_count, upgrade_cost, sell_price, initial_money in zip(count, upgrade, sell, money):
24 # Calculate maximum upgradeable items
25 # Formula: min(total_items, (total_money_from_selling + initial_money) / total_cost_per_upgrade)
26 # Where total_cost_per_upgrade = upgrade_cost + sell_price (opportunity cost)
27 max_upgradeable = min(
28 item_count,
29 (item_count * sell_price + initial_money) // (upgrade_cost + sell_price)
30 )
31 result.append(max_upgradeable)
32
33 return result
34
1class Solution {
2 /**
3 * Calculates the maximum number of upgrades possible for each item.
4 *
5 * @param count Array representing the initial count of each item
6 * @param upgrade Array representing the upgrade cost for each item
7 * @param sell Array representing the sell price for each item
8 * @param money Array representing the available money for each item
9 * @return Array containing the maximum upgrades possible for each item
10 */
11 public int[] maxUpgrades(int[] count, int[] upgrade, int[] sell, int[] money) {
12 int n = count.length;
13 int[] result = new int[n];
14
15 // Process each item independently
16 for (int i = 0; i < n; i++) {
17 // Calculate maximum upgrades based on two constraints:
18 // 1. Cannot upgrade more than the current count
19 // 2. Total cost of upgrades cannot exceed available funds
20
21 // Formula derivation:
22 // Let x be the number of items to upgrade
23 // Money from selling (count - x) items: (count - x) * sell
24 // Total available money: (count - x) * sell + money
25 // Cost to upgrade x items: x * upgrade
26 // Constraint: x * upgrade <= (count - x) * sell + money
27 // Solving for x: x <= (count * sell + money) / (upgrade + sell)
28
29 long totalFunds = (long) count[i] * sell[i] + money[i];
30 int totalCostPerUpgrade = upgrade[i] + sell[i];
31 int maxAffordableUpgrades = (int) (totalFunds / totalCostPerUpgrade);
32
33 // Take minimum of count limit and affordable upgrades
34 result[i] = Math.min(count[i], maxAffordableUpgrades);
35 }
36
37 return result;
38 }
39}
40
1class Solution {
2public:
3 vector<int> maxUpgrades(vector<int>& count, vector<int>& upgrade, vector<int>& sell, vector<int>& money) {
4 int n = count.size();
5 vector<int> result;
6
7 // Process each item type independently
8 for (int i = 0; i < n; ++i) {
9 // Calculate maximum possible upgrades for item i
10 // Strategy: We can sell some items to fund upgrades for the remaining items
11 // Total money available = initial money + money from selling items
12 // Let x be the number of items to upgrade
13 // We need: x * upgrade[i] <= money[i] + (count[i] - x) * sell[i]
14 // Solving for x: x <= (count[i] * sell[i] + money[i]) / (upgrade[i] + sell[i])
15
16 // Use long long to prevent integer overflow during multiplication
17 long long totalFunds = static_cast<long long>(count[i]) * sell[i] + money[i];
18 int totalCost = upgrade[i] + sell[i];
19 int maxPossibleUpgrades = static_cast<int>(totalFunds / totalCost);
20
21 // Cannot upgrade more items than we have
22 int actualUpgrades = min(count[i], maxPossibleUpgrades);
23 result.push_back(actualUpgrades);
24 }
25
26 return result;
27 }
28};
29
1/**
2 * Calculates the maximum number of upgrades possible for each item
3 * @param count - Array of current item counts
4 * @param upgrade - Array of upgrade costs for each item
5 * @param sell - Array of selling prices for each item
6 * @param money - Array of available money for each item
7 * @returns Array of maximum possible upgrades for each item
8 */
9function maxUpgrades(
10 count: number[],
11 upgrade: number[],
12 sell: number[],
13 money: number[],
14): number[] {
15 // Get the length of input arrays
16 const arrayLength: number = count.length;
17
18 // Initialize result array to store maximum upgrades for each item
19 const result: number[] = [];
20
21 // Iterate through each item
22 for (let index = 0; index < arrayLength; ++index) {
23 // Calculate maximum upgrades possible
24 // Formula: (current items * sell price + available money) / (upgrade cost + sell price)
25 // Use bitwise OR with 0 to truncate to integer (equivalent to Math.floor for positive numbers)
26 const maxPossibleUpgrades: number =
27 ((count[index] * sell[index] + money[index]) / (upgrade[index] + sell[index])) | 0;
28
29 // The actual maximum upgrades cannot exceed the current count
30 // Take the minimum between calculated upgrades and current count
31 result.push(Math.min(maxPossibleUpgrades, count[index]));
32 }
33
34 return result;
35}
36
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the input arrays. The algorithm iterates through all four arrays simultaneously using zip()
, performing a constant number of operations for each element (one arithmetic calculation with addition, multiplication, and integer division, followed by a min()
operation between two values). Since we process each element exactly once with constant-time operations, the overall time complexity is linear.
The space complexity is O(1)
if we exclude the space used for the output array ans
. The algorithm only uses a fixed amount of extra space for the loop variables (cnt
, cost
, income
, cash
) regardless of the input size. Including the output array, the space complexity would be O(n)
since we store one result for each input element.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Division by Zero Error
The Pitfall: If both upgrade[i]
and sell[i]
are 0 for any data center, the formula (cnt * income + cash) // (cost + income)
will cause a division by zero error.
Why it happens: While it might seem unlikely in a real scenario, edge cases where both upgrading and selling have zero cost/price could exist in test data.
Solution: Add a check before performing the division:
for item_count, upgrade_cost, sell_price, initial_money in zip(count, upgrade, sell, money):
# Handle edge case where both costs are zero
if upgrade_cost + sell_price == 0:
# If upgrade cost is 0, we can upgrade all servers
max_upgradeable = item_count
else:
max_upgradeable = min(
item_count,
(item_count * sell_price + initial_money) // (upgrade_cost + sell_price)
)
result.append(max_upgradeable)
2. Integer Overflow in Large Calculations
The Pitfall: The calculation item_count * sell_price + initial_money
could potentially overflow if the values are extremely large.
Why it happens: When multiplying large numbers (e.g., millions of servers with high sell prices), the intermediate result might exceed typical integer limits in some programming languages.
Solution: While Python handles arbitrary precision integers automatically, in other languages or for optimization, you might need to rearrange the formula to avoid overflow:
# Alternative calculation to minimize overflow risk
# Instead of: (cnt * sell + money) // (upgrade + sell)
# Use: cnt - max(0, (cnt * upgrade - money) // (upgrade + sell))
servers_to_sell = max(0, (item_count * upgrade_cost - initial_money + upgrade_cost + sell_price - 1) // (upgrade_cost + sell_price))
max_upgradeable = item_count - servers_to_sell
3. Incorrect Handling of Zero or Negative Values
The Pitfall: Not properly handling cases where money[i]
could be 0 or where sell[i]
might be greater than upgrade[i]
.
Why it happens: The formula assumes standard economic behavior, but edge cases might include scenarios where selling servers gives more money than upgrading costs.
Solution: Ensure proper handling of all value ranges:
for item_count, upgrade_cost, sell_price, initial_money in zip(count, upgrade, sell, money):
# Handle negative or zero counts
if item_count <= 0:
result.append(0)
continue
# Handle case where selling is more profitable than upgrade cost
if sell_price > upgrade_cost and initial_money >= 0:
# Can potentially upgrade all servers if selling generates profit
max_upgradeable = item_count
elif upgrade_cost + sell_price > 0:
max_upgradeable = min(
item_count,
max(0, (item_count * sell_price + initial_money) // (upgrade_cost + sell_price))
)
else:
max_upgradeable = item_count if upgrade_cost == 0 else 0
result.append(max_upgradeable)
What's the relationship between a tree and a graph?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!