0
0
DSA Typescriptprogramming~15 mins

Activity Selection Problem in DSA Typescript - Deep Dive

Choose your learning style9 modes available
Overview - Activity Selection Problem
What is it?
The Activity Selection Problem is about choosing the maximum number of activities that don't overlap in time. Each activity has a start time and an end time. The goal is to select activities so that no two chosen activities happen at the same time. This helps in scheduling tasks efficiently.
Why it matters
Without this problem's solution, scheduling tasks or events would be inefficient, leading to wasted time or resources. For example, if you book overlapping meetings, you can't attend all. Solving this problem helps in planning where time is limited and many tasks compete for it.
Where it fits
Before learning this, you should understand arrays and sorting basics. After this, you can explore more complex scheduling problems like interval graphs or dynamic programming approaches to scheduling.
Mental Model
Core Idea
Pick activities that finish earliest to leave room for more activities later.
Think of it like...
Imagine you have a single meeting room and many people want to use it. To fit the most meetings, you always let the meeting that ends soonest happen first, then pick the next meeting that starts after it ends, and so on.
Activities sorted by finish time:

Start:  | 1 | 3 | 0 | 5 | 8 | 5 |
Finish: | 2 | 4 | 6 | 7 | 9 | 9 |

Selection process:
[1-2] -> [3-4] -> [5-7] -> [8-9]

Diagram:
┌─────────┐
│ Activity│
├─────────┤
│ 1 - 2   │
│ 3 - 4   │
│ 5 - 7   │
│ 8 - 9   │
└─────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Activities and Time Slots
🤔
Concept: Introduce what activities are and how start and end times define them.
An activity is a task with a start time and an end time. For example, Activity A starts at 1 and ends at 2. Activities can overlap if one starts before another ends. We want to find which activities can fit without overlapping.
Result
You understand that activities are intervals on a timeline and overlapping means two intervals share some time.
Understanding activities as time intervals is key to seeing why some can't happen together.
2
FoundationSorting Activities by Finish Time
🤔
Concept: Sorting activities by their end times helps in making the best choices.
Given a list of activities, we sort them so the one that finishes earliest comes first. For example, activities [(1,2), (3,4), (0,6)] become [(1,2), (3,4), (0,6)] after sorting by finish time 2,4,6.
Result
Activities are ordered to consider earliest finishing ones first.
Sorting by finish time sets the stage for a greedy choice that leads to the best overall schedule.
3
IntermediateGreedy Choice: Selecting Earliest Finishing Activity
🤔Before reading on: Do you think picking the longest activity first or the earliest finishing activity first leads to more total activities? Commit to your answer.
Concept: Choosing the activity that finishes earliest leaves the most room for others.
Start with the first activity in the sorted list (earliest finish). Then pick the next activity that starts after the last selected activity ends. Repeat until no more activities fit.
Result
Selected activities maximize the number of non-overlapping tasks.
Choosing earliest finishing activities is a simple rule that guarantees the maximum number of activities.
4
IntermediateImplementing Activity Selection in TypeScript
🤔Before reading on: Will a simple loop checking start and end times suffice to select activities? Commit to your answer.
Concept: Use a loop to pick activities based on sorted finish times and start times.
Code example: function selectActivities(start: number[], finish: number[]): number[] { const n = start.length; const activities = start.map((s, i) => ({start: s, finish: finish[i], index: i})); activities.sort((a, b) => a.finish - b.finish); const selected: number[] = []; let lastFinish = -1; for (const activity of activities) { if (activity.start >= lastFinish) { selected.push(activity.index); lastFinish = activity.finish; } } return selected; } This picks the maximum set of activities without overlap.
Result
The function returns indices of selected activities maximizing count.
A simple loop with sorted activities efficiently solves the problem.
5
IntermediateDry Run Example with Sample Activities
🤔Before reading on: How many activities do you think can be selected from [(1,2), (3,4), (0,6), (5,7), (8,9), (5,9)]? Commit to your answer.
Concept: Walk through the algorithm step-by-step with real data.
Activities: Index Start Finish 0 1 2 1 3 4 2 0 6 3 5 7 4 8 9 5 5 9 Sorted by finish: 0(1,2), 1(3,4), 2(0,6), 3(5,7), 4(8,9), 5(5,9) Selection: Pick 0 (1,2) Next start >= 2: pick 1 (3,4) Next start >= 4: skip 2 (0,6), pick 3 (5,7) Next start >= 7: pick 4 (8,9) Skip 5 (5,9) because it overlaps Selected indices: [0,1,3,4]
Result
Four activities selected: indices 0,1,3,4.
Step-by-step tracing confirms the greedy method picks the maximum activities.
6
AdvancedHandling Edge Cases and Equal Finish Times
🤔Before reading on: If two activities finish at the same time, does picking either first affect the maximum count? Commit to your answer.
Concept: Understand how ties in finish times affect selection and how to handle them.
If two activities finish at the same time, picking either first does not reduce the maximum count. The algorithm can pick any of them as long as start times don't overlap. To keep consistency, stable sorting or tie-breakers by start time can be used.
Result
Algorithm remains correct even with equal finish times.
Knowing tie handling prevents bugs in real data with equal finish times.
7
ExpertExtending to Weighted Activity Selection Problem
🤔Before reading on: Does the greedy earliest finish time approach work if activities have different values or weights? Commit to your answer.
Concept: When activities have weights (values), the problem needs a different approach than greedy.
The weighted activity selection problem requires dynamic programming because picking earliest finishing activity may not maximize total weight. Instead, we consider all compatible activities and choose the best combination by comparing sums of weights.
Result
Greedy fails for weighted case; dynamic programming is needed.
Recognizing limits of greedy approach guides choosing correct algorithms for complex scheduling.
Under the Hood
The algorithm sorts activities by their finish times, then iterates through them once. It keeps track of the last selected activity's finish time and picks the next activity only if it starts after or exactly when the last one finished. This greedy choice ensures no overlaps and maximizes count because choosing earliest finishing activity leaves maximum room for others.
Why designed this way?
This approach was designed to solve scheduling efficiently without checking all subsets, which would be slow. Sorting and greedy selection reduce complexity from exponential to O(n log n) due to sorting. Alternatives like brute force were too slow for large inputs.
┌─────────────┐
│ Activities  │
│ (start,end) │
└─────┬───────┘
      │ Sort by finish time
      ▼
┌─────────────┐
│ Sorted list │
└─────┬───────┘
      │ Iterate and select
      ▼
┌─────────────┐
│ Selected    │
│ activities  │
└─────────────┘
Myth Busters - 3 Common Misconceptions
Quick: Does picking the longest activity first always maximize the number of activities? Commit yes or no.
Common Belief:Picking the longest activity first will maximize the number of activities scheduled.
Tap to reveal reality
Reality:Picking the longest activity first often reduces the total number of activities because it blocks more time, leaving less room for others.
Why it matters:Choosing longest activities first can lead to fewer tasks done, wasting available time.
Quick: Can the greedy earliest finish time method solve weighted activity selection? Commit yes or no.
Common Belief:The greedy earliest finish time method works for all activity selection problems, including weighted ones.
Tap to reveal reality
Reality:Greedy earliest finish time fails for weighted problems; dynamic programming is required to maximize total weight.
Why it matters:Using greedy for weighted cases leads to suboptimal schedules and lost value.
Quick: If two activities have the same finish time, does the order of selection affect the maximum count? Commit yes or no.
Common Belief:The order of activities with the same finish time affects the maximum number of activities selected.
Tap to reveal reality
Reality:The order does not affect the maximum count as long as the selection respects start times; any order works.
Why it matters:Worrying about tie order can complicate implementation unnecessarily.
Expert Zone
1
The greedy algorithm's correctness depends on the problem's optimal substructure and greedy choice properties, which are subtle and not always present in similar problems.
2
Stable sorting by finish time and then by start time can help maintain predictable selection order, which is useful in debugging and reproducibility.
3
In real systems, activities may have constraints beyond time (like resources), requiring extensions beyond the classic problem.
When NOT to use
Do not use this greedy approach when activities have weights or values; instead, use dynamic programming. Also avoid it when activities have complex constraints like multiple resources or dependencies.
Production Patterns
Used in scheduling meetings, CPU job scheduling, booking systems, and event planning where maximizing non-overlapping tasks is critical. Often combined with priority queues or interval trees for dynamic updates.
Connections
Interval Scheduling
Activity Selection is a classic example of interval scheduling problems.
Understanding activity selection helps grasp broader interval scheduling challenges in operating systems and networking.
Dynamic Programming
Weighted Activity Selection extends the problem requiring dynamic programming instead of greedy.
Knowing when greedy fails and DP is needed sharpens algorithm choice skills.
Project Management
Scheduling tasks without overlap is a core challenge in project management.
Algorithms like activity selection underpin tools that optimize resource and time allocation in projects.
Common Pitfalls
#1Selecting activities based on earliest start time instead of earliest finish time.
Wrong approach:activities.sort((a, b) => a.start - b.start); // Then select activities greedily by start time
Correct approach:activities.sort((a, b) => a.finish - b.finish); // Then select activities greedily by finish time
Root cause:Misunderstanding that earliest start does not guarantee maximum number of activities.
#2Trying to select overlapping activities by ignoring finish times.
Wrong approach:for (const activity of activities) { selected.push(activity.index); // no check for overlap }
Correct approach:let lastFinish = -1; for (const activity of activities) { if (activity.start >= lastFinish) { selected.push(activity.index); lastFinish = activity.finish; } }
Root cause:Ignoring the core constraint of non-overlapping intervals.
#3Using greedy approach for weighted activities expecting maximum total weight.
Wrong approach:Select activities greedily by earliest finish time ignoring weights.
Correct approach:Use dynamic programming to consider weights and compatibility of activities.
Root cause:Assuming greedy works for all variations of activity selection.
Key Takeaways
The Activity Selection Problem finds the maximum number of non-overlapping activities by always choosing the earliest finishing activity first.
Sorting activities by their finish times is essential to apply the greedy selection correctly and efficiently.
Greedy selection works because choosing the earliest finishing activity leaves the most room for others, maximizing total count.
This approach runs in O(n log n) time due to sorting, making it efficient for large inputs.
For weighted activities, greedy fails and dynamic programming is required to maximize total value.