Job Scheduling with Deadlines in DSA Rust - Time & Space Complexity
We want to understand how the time needed to schedule jobs grows as we add more jobs.
How does the number of jobs affect the work done by the scheduling algorithm?
Analyze the time complexity of the following code snippet.
fn job_scheduling(jobs: &mut Vec<(i32, i32)>) -> i32 {
jobs.sort_by(|a, b| b.0.cmp(&a.0));
let mut result = vec![-1; 100];
let mut count = 0;
for &(profit, deadline) in jobs.iter() {
for slot in (0..deadline).rev() {
if result[slot as usize] == -1 {
result[slot as usize] = profit;
count += profit;
break;
}
}
}
count
}
This code schedules jobs by profit and deadline to maximize total profit.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops - outer loop over all jobs, inner loop over possible time slots.
- How many times: Outer loop runs once per job (n times), inner loop runs up to the deadline (up to 100 times).
As the number of jobs grows, the algorithm checks more jobs and more slots for each job.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Up to 100 checks |
| 100 | Up to 10,000 checks |
| 1000 | Up to 100,000 checks |
Pattern observation: The work grows roughly by the product of the number of jobs and the maximum deadline.
Time Complexity: O(n * d) where n is number of jobs and d is maximum deadline (here fixed at 100).
This means if you double the number of jobs, the time needed roughly doubles, assuming deadline is fixed.
[X] Wrong: "The algorithm only loops once over the jobs, so it must be O(n)."
[OK] Correct: Because inside the job loop, it also loops over time slots, which can be up to the maximum deadline times, making it slower than just one loop.
Understanding how nested loops affect time helps you explain your code clearly and shows you can think about efficiency in real problems.
"What if we used a data structure to find free slots faster? How would the time complexity change?"
Practice
Job Scheduling with Deadlines problem?Solution
Step 1: Understand the problem goal
The problem asks to schedule jobs so that each job finishes before its deadline and the total profit is maximized.Step 2: Identify the objective
Maximizing total profit means choosing jobs with higher profit and fitting them before their deadlines.Final Answer:
Maximize total profit by scheduling jobs before their deadlines -> Option CQuick Check:
Goal = Maximize profit before deadlines [OK]
- Thinking the goal is to schedule all jobs
- Ignoring deadlines when scheduling
- Trying to minimize jobs instead of maximizing profit
Solution
Step 1: Identify the need for tracking free slots
We need to know which time slots are free to schedule jobs before their deadlines.Step 2: Choose a data structure for slot tracking
A vector of booleans can mark each slot as free or occupied efficiently.Final Answer:
Vec (vector) with boolean flags for slots -> Option AQuick Check:
Use Vec<bool> to track free slots [OK]
- Using HashMap which is unnecessary for fixed slots
- Using LinkedList which is inefficient for slot checking
- Using BinaryHeap which is for priority, not slot tracking
struct Job { id: char, deadline: usize, profit: usize }
fn job_scheduling(jobs: &mut Vec<Job>) -> Vec<char> {
jobs.sort_by(|a, b| b.profit.cmp(&a.profit));
let max_deadline = jobs.iter().map(|j| j.deadline).max().unwrap_or(0);
let mut slots = vec![false; max_deadline];
let mut result = Vec::new();
for job in jobs.iter() {
for slot in (0..job.deadline).rev() {
if !slots[slot] {
slots[slot] = true;
result.push(job.id);
break;
}
}
}
result
}
fn main() {
let mut jobs = vec![
Job { id: 'A', deadline: 2, profit: 100 },
Job { id: 'B', deadline: 1, profit: 19 },
Job { id: 'C', deadline: 2, profit: 27 },
Job { id: 'D', deadline: 1, profit: 25 },
Job { id: 'E', deadline: 3, profit: 15 },
];
let scheduled = job_scheduling(&mut jobs);
println!("{:?}", scheduled);
}Solution
Step 1: Sort jobs by profit descending
Sorted jobs: A(100,2), C(27,2), D(25,1), B(19,1), E(15,3)Step 2: Schedule jobs in latest free slot before deadline
Schedule A at slot 1 (0-based), C at slot 0, E at slot 2. D and B cannot be scheduled as slots 0 and 1 are taken.Final Answer:
['A', 'C', 'E'] -> Option DQuick Check:
Jobs scheduled = ['A', 'C', 'E'] [OK]
- Scheduling jobs in arrival order instead of profit order
- Assigning earliest slot instead of latest free slot
- Ignoring slot availability and deadlines
fn schedule_jobs(jobs: &mut Vec<(char, usize, usize)>) -> Vec<char> {
jobs.sort_by(|a, b| b.2.cmp(&a.2));
let max_deadline = jobs.iter().map(|j| j.1).max().unwrap_or(0);
let mut slots = vec![false; max_deadline];
let mut result = Vec::new();
for job in jobs.iter() {
for slot in 0..job.1 {
if !slots[slot] {
slots[slot] = true;
result.push(job.0);
break;
}
}
}
result
}Solution
Step 1: Check sorting order
Jobs are sorted by profit descending (b.2.cmp(&a.2)), which is correct to prioritize high-profit jobs.Step 2: Check slot assignment loop
The loop iterates from 0 to deadline-1, assigning the earliest available slot. The correct approach assigns the latest free slot before the deadline to leave earlier slots for future jobs with tighter deadlines, so the loop should be reversed using (0..job.1).rev().Final Answer:
Inner loop should iterate slots in reverse order to assign latest slot -> Option BQuick Check:
Assign latest free slot by looping backwards [OK]
- Assigning earliest slot instead of latest free slot
- Using wrong slot vector size (off-by-one)
- Storing wrong data in result vector
Solution
Step 1: Sort jobs by profit descending
Sorted: D(100,2), B(80,1), A(70,4), E(40,3), C(30,1)Step 2: Schedule jobs in latest free slot before deadline
Schedule B at slot 0 (deadline 1), D at slot 1 (deadline 2), E at slot 2 (deadline 3), A at slot 3 (deadline 4). C cannot be scheduled as slot 0 is taken.Step 3: Calculate total profit
Profits: B(80) + D(100) + E(40) + A(70) = 290Final Answer:
4 jobs, total profit 290 -> Option AQuick Check:
4 jobs scheduled, profit = 290 [OK]
- Scheduling fewer jobs than possible
- Ignoring slot availability and deadlines
- Adding profits of unscheduled jobs
Ready to prove it?
Pass the test and this pattern moves unknown
