Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You have an inventory of different colored balls, and there is a customer that wants orders balls of any color.
The customer weirdly values the colored balls. Each colored ball's value is the number of balls of that color you currently have in your inventory. For example, if you own 6 yellow balls, the customer would pay 6 for the first yellow ball. After the transaction, there are only 5 yellow balls left, so the next yellow ball is then valued at 5 (i.e., the value of the balls decreases as you sell more to the customer).
You are given an integer array, inventory, where inventory[i] represents the number of balls of the ith color that you initially own. You are also given an integer orders, which represents the total number of balls that the customer wants. You can sell the balls in any order.
Return the maximum total value that you can attain after selling orders colored balls. As the answer may be too large, return it modulo 109 + 7.
Example 1:
Input: inventory = [2,5], orders = 4 Output: 14 Explanation: Sell the 1st color 1 time (2) and the 2nd color 3 times (5 + 4 + 3). The maximum total value is 2 + 5 + 4 + 3 = 14.
Example 2:
Input: inventory = [3,5], orders = 6 Output: 19 Explanation: Sell the 1st color 2 times (3 + 2) and the 2nd color 4 times (5 + 4 + 3 + 2). The maximum total value is 3 + 2 + 5 + 4 + 3 + 2 = 19.
Constraints:
1 <= inventory.length <= 1051 <= inventory[i] <= 1091 <= orders <= min(sum(inventory[i]), 109)Problem summary: You have an inventory of different colored balls, and there is a customer that wants orders balls of any color. The customer weirdly values the colored balls. Each colored ball's value is the number of balls of that color you currently have in your inventory. For example, if you own 6 yellow balls, the customer would pay 6 for the first yellow ball. After the transaction, there are only 5 yellow balls left, so the next yellow ball is then valued at 5 (i.e., the value of the balls decreases as you sell more to the customer). You are given an integer array, inventory, where inventory[i] represents the number of balls of the ith color that you initially own. You are also given an integer orders, which represents the total number of balls that the customer wants. You can sell the balls in any order. Return the maximum total value that you can attain after selling orders colored balls. As
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Math · Binary Search · Greedy
[2,5] 4
[3,5] 6
maximum-running-time-of-n-computers)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1648: Sell Diminishing-Valued Colored Balls
class Solution {
private static final int MOD = (int) 1e9 + 7;
public int maxProfit(int[] inventory, int orders) {
Arrays.sort(inventory);
int n = inventory.length;
for (int i = 0, j = n - 1; i < j; ++i, --j) {
int t = inventory[i];
inventory[i] = inventory[j];
inventory[j] = t;
}
long ans = 0;
int i = 0;
while (orders > 0) {
while (i < n && inventory[i] >= inventory[0]) {
++i;
}
int nxt = i < n ? inventory[i] : 0;
int cnt = i;
long x = inventory[0] - nxt;
long tot = cnt * x;
if (tot > orders) {
int decr = orders / cnt;
long a1 = inventory[0] - decr + 1, an = inventory[0];
ans += (a1 + an) * decr / 2 * cnt;
ans += (a1 - 1) * (orders % cnt);
} else {
long a1 = nxt + 1, an = inventory[0];
ans += (a1 + an) * x / 2 * cnt;
inventory[0] = nxt;
}
orders -= tot;
ans %= MOD;
}
return (int) ans;
}
}
// Accepted solution for LeetCode #1648: Sell Diminishing-Valued Colored Balls
func maxProfit(inventory []int, orders int) int {
var mod int = 1e9 + 7
i, n, ans := 0, len(inventory), 0
sort.Ints(inventory)
for i, j := 0, n-1; i < j; i, j = i+1, j-1 {
inventory[i], inventory[j] = inventory[j], inventory[i]
}
for orders > 0 {
for i < n && inventory[i] >= inventory[0] {
i++
}
nxt := 0
if i < n {
nxt = inventory[i]
}
cnt := i
x := inventory[0] - nxt
tot := cnt * x
if tot > orders {
decr := orders / cnt
a1, an := inventory[0]-decr+1, inventory[0]
ans += (a1 + an) * decr / 2 * cnt
ans += (a1 - 1) * (orders % cnt)
} else {
a1, an := nxt+1, inventory[0]
ans += (a1 + an) * x / 2 * cnt
inventory[0] = nxt
}
orders -= tot
ans %= mod
}
return ans
}
# Accepted solution for LeetCode #1648: Sell Diminishing-Valued Colored Balls
class Solution:
def maxProfit(self, inventory: List[int], orders: int) -> int:
inventory.sort(reverse=True)
mod = 10**9 + 7
ans = i = 0
n = len(inventory)
while orders > 0:
while i < n and inventory[i] >= inventory[0]:
i += 1
nxt = 0
if i < n:
nxt = inventory[i]
cnt = i
x = inventory[0] - nxt
tot = cnt * x
if tot > orders:
decr = orders // cnt
a1, an = inventory[0] - decr + 1, inventory[0]
ans += (a1 + an) * decr // 2 * cnt
ans += (inventory[0] - decr) * (orders % cnt)
else:
a1, an = nxt + 1, inventory[0]
ans += (a1 + an) * x // 2 * cnt
inventory[0] = nxt
orders -= tot
ans %= mod
return ans
// Accepted solution for LeetCode #1648: Sell Diminishing-Valued Colored Balls
struct Solution;
const MOD: i64 = 1_000_000_007;
impl Solution {
fn max_profit(mut inventory: Vec<i32>, mut orders: i32) -> i32 {
let n = inventory.len();
inventory.sort_unstable();
let mut res: i64 = 0;
for i in (0..n).rev() {
let diff = if i > 0 {
inventory[i] - inventory[i - 1]
} else {
inventory[i]
};
let w = (n - i) as i32;
if orders >= diff * w {
res += (inventory[i] - diff + 1 + inventory[i]) as i64 * diff as i64 / 2 * w as i64;
res %= MOD;
orders -= diff * w;
} else {
let diff = orders / w;
res += (inventory[i] - diff + 1 + inventory[i]) as i64 * diff as i64 / 2 * w as i64;
res %= MOD;
orders -= diff * w;
let h = inventory[i] - diff;
while orders > 0 {
res += h as i64;
res %= MOD;
orders -= 1;
}
break;
}
}
res as i32
}
}
#[test]
fn test() {
let inventory = vec![2, 5];
let orders = 4;
let res = 14;
assert_eq!(Solution::max_profit(inventory, orders), res);
let inventory = vec![3, 5];
let orders = 6;
let res = 19;
assert_eq!(Solution::max_profit(inventory, orders), res);
let inventory = vec![2, 8, 4, 10, 6];
let orders = 20;
let res = 110;
assert_eq!(Solution::max_profit(inventory, orders), res);
let inventory = vec![2, 8, 4, 10, 6];
let orders = 20;
let res = 110;
assert_eq!(Solution::max_profit(inventory, orders), res);
let inventory = vec![1000000000];
let orders = 1000000000;
let res = 21;
assert_eq!(Solution::max_profit(inventory, orders), res);
}
// Accepted solution for LeetCode #1648: Sell Diminishing-Valued Colored Balls
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #1648: Sell Diminishing-Valued Colored Balls
// class Solution {
// private static final int MOD = (int) 1e9 + 7;
//
// public int maxProfit(int[] inventory, int orders) {
// Arrays.sort(inventory);
// int n = inventory.length;
// for (int i = 0, j = n - 1; i < j; ++i, --j) {
// int t = inventory[i];
// inventory[i] = inventory[j];
// inventory[j] = t;
// }
// long ans = 0;
// int i = 0;
// while (orders > 0) {
// while (i < n && inventory[i] >= inventory[0]) {
// ++i;
// }
// int nxt = i < n ? inventory[i] : 0;
// int cnt = i;
// long x = inventory[0] - nxt;
// long tot = cnt * x;
// if (tot > orders) {
// int decr = orders / cnt;
// long a1 = inventory[0] - decr + 1, an = inventory[0];
// ans += (a1 + an) * decr / 2 * cnt;
// ans += (a1 - 1) * (orders % cnt);
// } else {
// long a1 = nxt + 1, an = inventory[0];
// ans += (a1 + an) * x / 2 * cnt;
// inventory[0] = nxt;
// }
// orders -= tot;
// ans %= MOD;
// }
// return (int) ans;
// }
// }
Use this to step through a reusable interview workflow for this problem.
Check every element from left to right until we find the target or exhaust the array. Each comparison is O(1), and we may visit all n elements, giving O(n). No extra space needed.
Each comparison eliminates half the remaining search space. After k comparisons, the space is n/2ᵏ. We stop when the space is 1, so k = log₂ n. No extra memory needed — just two pointers (lo, hi).
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.
Wrong move: Setting `lo = mid` or `hi = mid` can stall and create an infinite loop.
Usually fails on: Two-element ranges never converge.
Fix: Use `lo = mid + 1` or `hi = mid - 1` where appropriate.
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.