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.
Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.
Note that intervals which only touch at a point are non-overlapping. For example, [1, 2] and [2, 3] are non-overlapping.
Example 1:
Input: intervals = [[1,2],[2,3],[3,4],[1,3]] Output: 1 Explanation: [1,3] can be removed and the rest of the intervals are non-overlapping.
Example 2:
Input: intervals = [[1,2],[1,2],[1,2]] Output: 2 Explanation: You need to remove two [1,2] to make the rest of the intervals non-overlapping.
Example 3:
Input: intervals = [[1,2],[2,3]] Output: 0 Explanation: You don't need to remove any of the intervals since they're already non-overlapping.
Constraints:
1 <= intervals.length <= 105intervals[i].length == 2-5 * 104 <= starti < endi <= 5 * 104Problem summary: Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping. Note that intervals which only touch at a point are non-overlapping. For example, [1, 2] and [2, 3] are non-overlapping.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Dynamic Programming · Greedy
[[1,2],[2,3],[3,4],[1,3]]
[[1,2],[1,2],[1,2]]
[[1,2],[2,3]]
minimum-number-of-arrows-to-burst-balloons)determine-if-two-events-have-conflict)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #435: Non-overlapping Intervals
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[1] - b[1]);
int ans = intervals.length;
int pre = Integer.MIN_VALUE;
for (var e : intervals) {
int l = e[0], r = e[1];
if (pre <= l) {
--ans;
pre = r;
}
}
return ans;
}
}
// Accepted solution for LeetCode #435: Non-overlapping Intervals
func eraseOverlapIntervals(intervals [][]int) int {
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][1] < intervals[j][1]
})
ans := len(intervals)
pre := math.MinInt32
for _, e := range intervals {
l, r := e[0], e[1]
if pre <= l {
ans--
pre = r
}
}
return ans
}
# Accepted solution for LeetCode #435: Non-overlapping Intervals
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
intervals.sort(key=lambda x: x[1])
ans = len(intervals)
pre = -inf
for l, r in intervals:
if pre <= l:
ans -= 1
pre = r
return ans
// Accepted solution for LeetCode #435: Non-overlapping Intervals
impl Solution {
pub fn erase_overlap_intervals(mut intervals: Vec<Vec<i32>>) -> i32 {
intervals.sort_by(|a, b| a[0].cmp(&b[0]));
let mut res = 0;
let mut prev_end = intervals[0][1];
for interval in intervals.iter().skip(1) {
let start = interval[0];
let end = interval[1];
if start >= prev_end {
prev_end = end;
} else {
res += 1;
prev_end = prev_end.min(end);
}
}
res
}
}
// Accepted solution for LeetCode #435: Non-overlapping Intervals
function eraseOverlapIntervals(intervals: number[][]): number {
intervals.sort((a, b) => a[1] - b[1]);
let [ans, pre] = [intervals.length, -Infinity];
for (const [l, r] of intervals) {
if (pre <= l) {
--ans;
pre = r;
}
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Pure recursion explores every possible choice at each step. With two choices per state (take or skip), the decision tree has 2ⁿ leaves. The recursion stack uses O(n) space. Many subproblems are recomputed exponentially many times.
Each cell in the DP table is computed exactly once from previously solved subproblems. The table dimensions determine both time and space. Look for the state variables — each unique combination of state values is one cell. Often a rolling array can reduce space by one dimension.
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: 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.
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.