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 are given an integer n representing the number of houses on a number line, numbered from 0 to n - 1.
Additionally, you are given a 2D integer array offers where offers[i] = [starti, endi, goldi], indicating that ith buyer wants to buy all the houses from starti to endi for goldi amount of gold.
As a salesman, your goal is to maximize your earnings by strategically selecting and selling houses to buyers.
Return the maximum amount of gold you can earn.
Note that different buyers can't buy the same house, and some houses may remain unsold.
Example 1:
Input: n = 5, offers = [[0,0,1],[0,2,2],[1,3,2]] Output: 3 Explanation: There are 5 houses numbered from 0 to 4 and there are 3 purchase offers. We sell houses in the range [0,0] to 1st buyer for 1 gold and houses in the range [1,3] to 3rd buyer for 2 golds. It can be proven that 3 is the maximum amount of gold we can achieve.
Example 2:
Input: n = 5, offers = [[0,0,1],[0,2,10],[1,3,2]] Output: 10 Explanation: There are 5 houses numbered from 0 to 4 and there are 3 purchase offers. We sell houses in the range [0,2] to 2nd buyer for 10 golds. It can be proven that 10 is the maximum amount of gold we can achieve.
Constraints:
1 <= n <= 1051 <= offers.length <= 105offers[i].length == 30 <= starti <= endi <= n - 11 <= goldi <= 103Problem summary: You are given an integer n representing the number of houses on a number line, numbered from 0 to n - 1. Additionally, you are given a 2D integer array offers where offers[i] = [starti, endi, goldi], indicating that ith buyer wants to buy all the houses from starti to endi for goldi amount of gold. As a salesman, your goal is to maximize your earnings by strategically selecting and selling houses to buyers. Return the maximum amount of gold you can earn. Note that different buyers can't buy the same house, and some houses may remain unsold.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Binary Search · Dynamic Programming
5 [[0,0,1],[0,2,2],[1,3,2]]
5 [[0,0,1],[0,2,10],[1,3,2]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2830: Maximize the Profit as the Salesman
class Solution {
public int maximizeTheProfit(int n, List<List<Integer>> offers) {
offers.sort((a, b) -> a.get(1) - b.get(1));
n = offers.size();
int[] f = new int[n + 1];
int[] g = new int[n];
for (int i = 0; i < n; ++i) {
g[i] = offers.get(i).get(1);
}
for (int i = 1; i <= n; ++i) {
var o = offers.get(i - 1);
int j = search(g, o.get(0));
f[i] = Math.max(f[i - 1], f[j] + o.get(2));
}
return f[n];
}
private int search(int[] nums, int x) {
int l = 0, r = nums.length;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] >= x) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
}
// Accepted solution for LeetCode #2830: Maximize the Profit as the Salesman
func maximizeTheProfit(n int, offers [][]int) int {
sort.Slice(offers, func(i, j int) bool { return offers[i][1] < offers[j][1] })
n = len(offers)
f := make([]int, n+1)
g := []int{}
for _, o := range offers {
g = append(g, o[1])
}
for i := 1; i <= n; i++ {
j := sort.SearchInts(g, offers[i-1][0])
f[i] = max(f[i-1], f[j]+offers[i-1][2])
}
return f[n]
}
# Accepted solution for LeetCode #2830: Maximize the Profit as the Salesman
class Solution:
def maximizeTheProfit(self, n: int, offers: List[List[int]]) -> int:
offers.sort(key=lambda x: x[1])
f = [0] * (len(offers) + 1)
g = [x[1] for x in offers]
for i, (s, _, v) in enumerate(offers, 1):
j = bisect_left(g, s)
f[i] = max(f[i - 1], f[j] + v)
return f[-1]
// Accepted solution for LeetCode #2830: Maximize the Profit as the Salesman
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #2830: Maximize the Profit as the Salesman
// class Solution {
// public int maximizeTheProfit(int n, List<List<Integer>> offers) {
// offers.sort((a, b) -> a.get(1) - b.get(1));
// n = offers.size();
// int[] f = new int[n + 1];
// int[] g = new int[n];
// for (int i = 0; i < n; ++i) {
// g[i] = offers.get(i).get(1);
// }
// for (int i = 1; i <= n; ++i) {
// var o = offers.get(i - 1);
// int j = search(g, o.get(0));
// f[i] = Math.max(f[i - 1], f[j] + o.get(2));
// }
// return f[n];
// }
//
// private int search(int[] nums, int x) {
// int l = 0, r = nums.length;
// while (l < r) {
// int mid = (l + r) >> 1;
// if (nums[mid] >= x) {
// r = mid;
// } else {
// l = mid + 1;
// }
// }
// return l;
// }
// }
// Accepted solution for LeetCode #2830: Maximize the Profit as the Salesman
function maximizeTheProfit(n: number, offers: number[][]): number {
offers.sort((a, b) => a[1] - b[1]);
n = offers.length;
const f: number[] = Array(n + 1).fill(0);
const g = offers.map(x => x[1]);
const search = (x: number) => {
let l = 0;
let r = n;
while (l < r) {
const mid = (l + r) >> 1;
if (g[mid] >= x) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
};
for (let i = 1; i <= n; ++i) {
const j = search(offers[i - 1][0]);
f[i] = Math.max(f[i - 1], f[j] + offers[i - 1][2]);
}
return f[n];
}
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: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.
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: An incomplete state merges distinct subproblems and caches incorrect answers.
Usually fails on: Correctness breaks on cases that differ only in hidden state.
Fix: Define state so each unique subproblem maps to one DP cell.