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.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
You are given a 0-indexed m * n integer matrix values, representing the values of m * n different items in m different shops. Each shop has n items where the jth item in the ith shop has a value of values[i][j]. Additionally, the items in the ith shop are sorted in non-increasing order of value. That is, values[i][j] >= values[i][j + 1] for all 0 <= j < n - 1.
On each day, you would like to buy a single item from one of the shops. Specifically, On the dth day you can:
i.j for the price of values[i][j] * d. That is, find the greatest index j such that item j was never bought before, and buy it for the price of values[i][j] * d.Note that all items are pairwise different. For example, if you have bought item 0 from shop 1, you can still buy item 0 from any other shop.
Return the maximum amount of money that can be spent on buying all m * n products.
Example 1:
Input: values = [[8,5,2],[6,4,1],[9,7,3]] Output: 285 Explanation: On the first day, we buy product 2 from shop 1 for a price of values[1][2] * 1 = 1. On the second day, we buy product 2 from shop 0 for a price of values[0][2] * 2 = 4. On the third day, we buy product 2 from shop 2 for a price of values[2][2] * 3 = 9. On the fourth day, we buy product 1 from shop 1 for a price of values[1][1] * 4 = 16. On the fifth day, we buy product 1 from shop 0 for a price of values[0][1] * 5 = 25. On the sixth day, we buy product 0 from shop 1 for a price of values[1][0] * 6 = 36. On the seventh day, we buy product 1 from shop 2 for a price of values[2][1] * 7 = 49. On the eighth day, we buy product 0 from shop 0 for a price of values[0][0] * 8 = 64. On the ninth day, we buy product 0 from shop 2 for a price of values[2][0] * 9 = 81. Hence, our total spending is equal to 285. It can be shown that 285 is the maximum amount of money that can be spent buying all m * n products.
Example 2:
Input: values = [[10,8,6,4,2],[9,7,5,3,2]] Output: 386 Explanation: On the first day, we buy product 4 from shop 0 for a price of values[0][4] * 1 = 2. On the second day, we buy product 4 from shop 1 for a price of values[1][4] * 2 = 4. On the third day, we buy product 3 from shop 1 for a price of values[1][3] * 3 = 9. On the fourth day, we buy product 3 from shop 0 for a price of values[0][3] * 4 = 16. On the fifth day, we buy product 2 from shop 1 for a price of values[1][2] * 5 = 25. On the sixth day, we buy product 2 from shop 0 for a price of values[0][2] * 6 = 36. On the seventh day, we buy product 1 from shop 1 for a price of values[1][1] * 7 = 49. On the eighth day, we buy product 1 from shop 0 for a price of values[0][1] * 8 = 64 On the ninth day, we buy product 0 from shop 1 for a price of values[1][0] * 9 = 81. On the tenth day, we buy product 0 from shop 0 for a price of values[0][0] * 10 = 100. Hence, our total spending is equal to 386. It can be shown that 386 is the maximum amount of money that can be spent buying all m * n products.
Constraints:
1 <= m == values.length <= 101 <= n == values[i].length <= 1041 <= values[i][j] <= 106values[i] are sorted in non-increasing order.Problem summary: You are given a 0-indexed m * n integer matrix values, representing the values of m * n different items in m different shops. Each shop has n items where the jth item in the ith shop has a value of values[i][j]. Additionally, the items in the ith shop are sorted in non-increasing order of value. That is, values[i][j] >= values[i][j + 1] for all 0 <= j < n - 1. On each day, you would like to buy a single item from one of the shops. Specifically, On the dth day you can: Pick any shop i. Buy the rightmost available item j for the price of values[i][j] * d. That is, find the greatest index j such that item j was never bought before, and buy it for the price of values[i][j] * d. Note that all items are pairwise different. For example, if you have bought item 0 from shop 1, you can still buy item 0 from any other shop. Return the maximum amount of money that can be spent on buying all m * n
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Greedy
[[8,5,2],[6,4,1],[9,7,3]]
[[10,8,6,4,2],[9,7,5,3,2]]
maximum-points-you-can-obtain-from-cards)maximum-score-from-performing-multiplication-operations)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2931: Maximum Spending After Buying Items
class Solution {
public long maxSpending(int[][] values) {
int m = values.length, n = values[0].length;
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
for (int i = 0; i < m; ++i) {
pq.offer(new int[] {values[i][n - 1], i, n - 1});
}
long ans = 0;
for (int d = 1; !pq.isEmpty(); ++d) {
var p = pq.poll();
int v = p[0], i = p[1], j = p[2];
ans += (long) v * d;
if (j > 0) {
pq.offer(new int[] {values[i][j - 1], i, j - 1});
}
}
return ans;
}
}
// Accepted solution for LeetCode #2931: Maximum Spending After Buying Items
func maxSpending(values [][]int) (ans int64) {
pq := hp{}
n := len(values[0])
for i, row := range values {
heap.Push(&pq, tuple{row[n-1], i, n - 1})
}
for d := 1; len(pq) > 0; d++ {
p := heap.Pop(&pq).(tuple)
ans += int64(p.v * d)
if p.j > 0 {
heap.Push(&pq, tuple{values[p.i][p.j-1], p.i, p.j - 1})
}
}
return
}
type tuple struct{ v, i, j int }
type hp []tuple
func (h hp) Len() int { return len(h) }
func (h hp) Less(i, j int) bool { return h[i].v < h[j].v }
func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v any) { *h = append(*h, v.(tuple)) }
func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }
# Accepted solution for LeetCode #2931: Maximum Spending After Buying Items
class Solution:
def maxSpending(self, values: List[List[int]]) -> int:
n = len(values[0])
pq = [(row[-1], i, n - 1) for i, row in enumerate(values)]
heapify(pq)
ans = d = 0
while pq:
d += 1
v, i, j = heappop(pq)
ans += v * d
if j:
heappush(pq, (values[i][j - 1], i, j - 1))
return ans
// Accepted solution for LeetCode #2931: Maximum Spending After Buying Items
/**
* [2931] Maximum Spending After Buying Items
*/
pub struct Solution {}
// submission codes start here
use std::cmp::Ordering;
use std::collections::BinaryHeap;
#[derive(Debug, PartialEq, Eq)]
struct Item {
price: i64,
shop: usize,
pos: usize,
}
impl Ord for Item {
fn cmp(&self, other: &Self) -> Ordering {
other.price.cmp(&self.price)
}
}
impl PartialOrd for Item {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Solution {
pub fn max_spending(values: Vec<Vec<i32>>) -> i64 {
let (m, n) = (values.len(), values[0].len());
let mut heap = BinaryHeap::with_capacity(values.len());
let mut result = 0;
for i in 0..m {
heap.push(Item {
price: values[i][n - 1] as i64,
shop: i,
pos: n - 1,
});
}
let mut day = 1;
while let Some(top) = heap.pop() {
result += top.price * day;
day += 1;
if top.pos > 0 {
heap.push(Item {
price: values[top.shop][top.pos - 1] as i64,
shop: top.shop,
pos: top.pos - 1,
})
}
}
result
}
}
// submission codes end
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_2931() {
assert_eq!(
285,
Solution::max_spending(vec![vec![8, 5, 2], vec![6, 4, 1], vec![9, 7, 3]])
);
}
}
// Accepted solution for LeetCode #2931: Maximum Spending After Buying Items
function maxSpending(values: number[][]): number {
const m = values.length;
const n = values[0].length;
const pq = new PriorityQueue({ compare: (a, b) => a[0] - b[0] });
for (let i = 0; i < m; ++i) {
pq.enqueue([values[i][n - 1], i, n - 1]);
}
let ans = 0;
for (let d = 1; !pq.isEmpty(); ++d) {
const [v, i, j] = pq.dequeue()!;
ans += v * d;
if (j > 0) {
pq.enqueue([values[i][j - 1], i, j - 1]);
}
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Try every possible combination of choices. With n items each having two states (include/exclude), the search space is 2ⁿ. Evaluating each combination takes O(n), giving O(n × 2ⁿ). The recursion stack or subset storage uses O(n) space.
Greedy algorithms typically sort the input (O(n log n)) then make a single pass (O(n)). The sort dominates. If the input is already sorted or the greedy choice can be computed without sorting, time drops to O(n). Proving greedy correctness (exchange argument) is harder than the implementation.
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: 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.