From 52d1eca3cc3ac7bc82173ae757cf80008187380b Mon Sep 17 00:00:00 2001 From: B Durga sai Rohan Date: Thu, 9 Oct 2025 13:47:15 +0530 Subject: [PATCH 1/7] Create job_scheduling.py --- dynamic_programming/job_scheduling.py | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 dynamic_programming/job_scheduling.py diff --git a/dynamic_programming/job_scheduling.py b/dynamic_programming/job_scheduling.py new file mode 100644 index 000000000000..a13dd2d41a97 --- /dev/null +++ b/dynamic_programming/job_scheduling.py @@ -0,0 +1,40 @@ +""" +Weighted Job Scheduling Problem +Given jobs with start time, end time, and profit, find the maximum profit +subset of non-overlapping jobs. +""" + +from bisect import bisect_right + +def job_scheduling(jobs): + """ + >>> jobs = [(1, 3, 50), (3, 5, 20), (0, 6, 100), (4, 6, 70), (3, 8, 60)] + >>> job_scheduling(jobs) + 120 + >>> jobs = [(1, 2, 50), (3, 5, 20), (6, 19, 100), (2, 100, 200)] + >>> job_scheduling(jobs) + 250 + """ + # Sort jobs by end time + jobs.sort(key=lambda x: x[1]) + n = len(jobs) + # dp[i] stores max profit including jobs[i] + dp = [0] * n + dp[0] = jobs[0][2] + + # Store end times separately for binary search + end_times = [job[1] for job in jobs] + + for i in range(1, n): + profit_incl = jobs[i][2] + # Find last non-conflicting job using binary search + index = bisect_right(end_times, jobs[i][0]-1) - 1 + if index != -1: + profit_incl += dp[index] + dp[i] = max(profit_incl, dp[i-1]) + return dp[-1] + + +if __name__ == "__main__": + import doctest + doctest.testmod() From 34c7ecdf6d287a3ed164c74b4d4d350ad7bef2b3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 08:20:28 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dynamic_programming/job_scheduling.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dynamic_programming/job_scheduling.py b/dynamic_programming/job_scheduling.py index a13dd2d41a97..9c29cc2ba318 100644 --- a/dynamic_programming/job_scheduling.py +++ b/dynamic_programming/job_scheduling.py @@ -6,6 +6,7 @@ from bisect import bisect_right + def job_scheduling(jobs): """ >>> jobs = [(1, 3, 50), (3, 5, 20), (0, 6, 100), (4, 6, 70), (3, 8, 60)] @@ -28,13 +29,14 @@ def job_scheduling(jobs): for i in range(1, n): profit_incl = jobs[i][2] # Find last non-conflicting job using binary search - index = bisect_right(end_times, jobs[i][0]-1) - 1 + index = bisect_right(end_times, jobs[i][0] - 1) - 1 if index != -1: profit_incl += dp[index] - dp[i] = max(profit_incl, dp[i-1]) + dp[i] = max(profit_incl, dp[i - 1]) return dp[-1] if __name__ == "__main__": import doctest + doctest.testmod() From 6b73c3821b53c3095a48ba19e6959fdeab80573f Mon Sep 17 00:00:00 2001 From: B Durga sai Rohan Date: Thu, 9 Oct 2025 14:30:22 +0530 Subject: [PATCH 3/7] Update job_scheduling.py --- dynamic_programming/job_scheduling.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/dynamic_programming/job_scheduling.py b/dynamic_programming/job_scheduling.py index 9c29cc2ba318..d74d0b5c5b80 100644 --- a/dynamic_programming/job_scheduling.py +++ b/dynamic_programming/job_scheduling.py @@ -17,7 +17,7 @@ def job_scheduling(jobs): 250 """ # Sort jobs by end time - jobs.sort(key=lambda x: x[1]) + jobs = sorted(jobs, key=lambda x: x[1]) n = len(jobs) # dp[i] stores max profit including jobs[i] dp = [0] * n @@ -34,9 +34,3 @@ def job_scheduling(jobs): profit_incl += dp[index] dp[i] = max(profit_incl, dp[i - 1]) return dp[-1] - - -if __name__ == "__main__": - import doctest - - doctest.testmod() From 97130b5ac8d9014111eb1faf4c783d818d4c245d Mon Sep 17 00:00:00 2001 From: B Durga sai Rohan Date: Thu, 9 Oct 2025 15:21:32 +0530 Subject: [PATCH 4/7] Update job_scheduling.py --- dynamic_programming/job_scheduling.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dynamic_programming/job_scheduling.py b/dynamic_programming/job_scheduling.py index d74d0b5c5b80..096e86d3e6f0 100644 --- a/dynamic_programming/job_scheduling.py +++ b/dynamic_programming/job_scheduling.py @@ -16,6 +16,8 @@ def job_scheduling(jobs): >>> job_scheduling(jobs) 250 """ + if not jobs: + return 0 # Sort jobs by end time jobs = sorted(jobs, key=lambda x: x[1]) n = len(jobs) From e9d90ee9f5ed691584fb44f38ea9c93016e4de72 Mon Sep 17 00:00:00 2001 From: B Durga sai Rohan Date: Thu, 9 Oct 2025 15:59:50 +0530 Subject: [PATCH 5/7] Update job_scheduling.py --- dynamic_programming/job_scheduling.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dynamic_programming/job_scheduling.py b/dynamic_programming/job_scheduling.py index 096e86d3e6f0..d73d7c74bc8a 100644 --- a/dynamic_programming/job_scheduling.py +++ b/dynamic_programming/job_scheduling.py @@ -2,12 +2,14 @@ Weighted Job Scheduling Problem Given jobs with start time, end time, and profit, find the maximum profit subset of non-overlapping jobs. +https://en.wikipedia.org/wiki/Weighted_interval_scheduling """ from bisect import bisect_right +from typing import List, Tuple -def job_scheduling(jobs): +def job_scheduling(jobs: List[Tuple[int, int, int]]) -> int: """ >>> jobs = [(1, 3, 50), (3, 5, 20), (0, 6, 100), (4, 6, 70), (3, 8, 60)] >>> job_scheduling(jobs) @@ -18,21 +20,19 @@ def job_scheduling(jobs): """ if not jobs: return 0 - # Sort jobs by end time - jobs = sorted(jobs, key=lambda x: x[1]) + + jobs.sort(key=lambda x: x[1]) n = len(jobs) - # dp[i] stores max profit including jobs[i] dp = [0] * n dp[0] = jobs[0][2] - - # Store end times separately for binary search end_times = [job[1] for job in jobs] for i in range(1, n): profit_incl = jobs[i][2] - # Find last non-conflicting job using binary search - index = bisect_right(end_times, jobs[i][0] - 1) - 1 + # ✅ allow jobs that start when another ends + index = bisect_right(end_times, jobs[i][0]) - 1 if index != -1: profit_incl += dp[index] dp[i] = max(profit_incl, dp[i - 1]) + return dp[-1] From 0aa46a00fb538e126c221b176c9ed3c433db0faa Mon Sep 17 00:00:00 2001 From: B Durga sai Rohan Date: Thu, 9 Oct 2025 16:01:28 +0530 Subject: [PATCH 6/7] Update job_scheduling.py --- dynamic_programming/job_scheduling.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dynamic_programming/job_scheduling.py b/dynamic_programming/job_scheduling.py index d73d7c74bc8a..36f18ddc4d83 100644 --- a/dynamic_programming/job_scheduling.py +++ b/dynamic_programming/job_scheduling.py @@ -6,10 +6,9 @@ """ from bisect import bisect_right -from typing import List, Tuple -def job_scheduling(jobs: List[Tuple[int, int, int]]) -> int: +def job_scheduling(jobs: list[tuple[int, int, int]]) -> int: """ >>> jobs = [(1, 3, 50), (3, 5, 20), (0, 6, 100), (4, 6, 70), (3, 8, 60)] >>> job_scheduling(jobs) @@ -29,8 +28,7 @@ def job_scheduling(jobs: List[Tuple[int, int, int]]) -> int: for i in range(1, n): profit_incl = jobs[i][2] - # ✅ allow jobs that start when another ends - index = bisect_right(end_times, jobs[i][0]) - 1 + index = bisect_right(end_times, jobs[i][0]) - 1 # allow adjacent jobs if index != -1: profit_incl += dp[index] dp[i] = max(profit_incl, dp[i - 1]) From dc23e00259e91419860b385bac0e366793d5b55e Mon Sep 17 00:00:00 2001 From: B Durga sai Rohan Date: Thu, 9 Oct 2025 16:44:07 +0530 Subject: [PATCH 7/7] Update job_scheduling.py --- dynamic_programming/job_scheduling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic_programming/job_scheduling.py b/dynamic_programming/job_scheduling.py index 36f18ddc4d83..67bdb547f25f 100644 --- a/dynamic_programming/job_scheduling.py +++ b/dynamic_programming/job_scheduling.py @@ -20,7 +20,7 @@ def job_scheduling(jobs: list[tuple[int, int, int]]) -> int: if not jobs: return 0 - jobs.sort(key=lambda x: x[1]) + jobs.sort(key=lambda job: job[1]) n = len(jobs) dp = [0] * n dp[0] = jobs[0][2]