Skip to content

Commit 7ec28ac

Browse files
committed
feat: add Weighted Interval Scheduling using DP and Binary Search
1 parent 08d8c6b commit 7ec28ac

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Solves the Weighted Interval Scheduling problem.
3+
*
4+
* Given intervals with start time, end time, and profit,
5+
* returns the maximum profit such that no intervals overlap.
6+
*
7+
* Uses Dynamic Programming + Binary Search.
8+
*
9+
* Time Complexity: O(n log n)
10+
* Space Complexity: O(n)
11+
*
12+
* @param {{start:number, end:number, profit:number}[]} intervals
13+
* @returns {number}
14+
*/
15+
16+
const weightedIntervalScheduling = (intervals) => {
17+
if (!Array.isArray(intervals)) {
18+
throw new Error('Input must be an array of intervals')
19+
}
20+
21+
if (intervals.length === 0) return 0
22+
23+
// Sort intervals by end time
24+
intervals.sort((a, b) => a.end - b.end)
25+
26+
const n = intervals.length
27+
const dp = Array(n).fill(0)
28+
29+
dp[0] = intervals[0].profit
30+
31+
// Binary search to find last non-overlapping interval
32+
const findLastNonOverlapping = (index) => {
33+
let left = 0
34+
let right = index - 1
35+
36+
while (left <= right) {
37+
const mid = Math.floor((left + right) / 2)
38+
39+
if (intervals[mid].end <= intervals[index].start) {
40+
if (intervals[mid + 1]?.end <= intervals[index].start) {
41+
left = mid + 1
42+
} else {
43+
return mid
44+
}
45+
} else {
46+
right = mid - 1
47+
}
48+
}
49+
50+
return -1
51+
}
52+
53+
for (let i = 1; i < n; i++) {
54+
let includeProfit = intervals[i].profit
55+
const lastIndex = findLastNonOverlapping(i)
56+
57+
if (lastIndex !== -1) {
58+
includeProfit += dp[lastIndex]
59+
}
60+
61+
dp[i] = Math.max(dp[i - 1], includeProfit)
62+
}
63+
64+
return dp[n - 1]
65+
}
66+
67+
export { weightedIntervalScheduling }
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { weightedIntervalScheduling } from '../WeightedIntervalScheduling'
2+
3+
test('basic weighted interval scheduling', () => {
4+
const intervals = [
5+
{ start: 1, end: 3, profit: 5 },
6+
{ start: 2, end: 5, profit: 6 },
7+
{ start: 4, end: 6, profit: 5 },
8+
{ start: 6, end: 7, profit: 4 },
9+
{ start: 5, end: 8, profit: 11 },
10+
{ start: 7, end: 9, profit: 2 }
11+
]
12+
13+
expect(weightedIntervalScheduling(intervals)).toBe(17)
14+
})
15+
16+
test('empty intervals', () => {
17+
expect(weightedIntervalScheduling([])).toBe(0)
18+
})
19+
20+
test('single interval', () => {
21+
expect(
22+
weightedIntervalScheduling([{ start: 1, end: 2, profit: 10 }])
23+
).toBe(10)
24+
})

0 commit comments

Comments
 (0)