Bird
Raised Fist0
DSA Javascriptprogramming~15 mins

Activity Selection Problem in DSA Javascript - Deep Dive

Choose your learning style10 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 from a list of activities, each with a start and end time. You want to attend as many activities as possible without any two happening at the same time. This problem helps us understand how to make the best choices when resources like time are limited.
Why it matters
Without this problem's solution, we might waste time trying to attend overlapping activities, missing out on many others. It shows how to plan efficiently when you have limited time and many options. This concept applies to scheduling meetings, booking rooms, or planning tasks in daily life or computer systems.
Where it fits
Before learning this, you should understand arrays, sorting, and basic loops. After this, you can explore greedy algorithms more deeply and study other scheduling problems like job sequencing or interval partitioning.
Mental Model
Core Idea
Pick the earliest finishing activity first to leave room for as many activities as possible afterward.
Think of it like...
Imagine you have a single chair and many friends want to sit for a chat, each for a different time. To let the most friends sit, you let the one who finishes talking earliest take the chair first, so others can use it after.
Activities sorted by finish time:
┌─────────────┐
│ Activity 1  │ Finish at 2
├─────────────┤
│ Activity 2  │ Finish at 4
├─────────────┤
│ Activity 3  │ Finish at 6
├─────────────┤
│ Activity 4  │ Finish at 8
└─────────────┘

Select Activity 1 first, then next that starts after 2, and so on.
Build-Up - 7 Steps
1
FoundationUnderstanding Activities and Time Slots
🤔
Concept: Activities have start and end times, and we want to find which ones can fit without overlapping.
Imagine you have a list of activities like [{start:1, end:2}, {start:3, end:4}, {start:0, end:6}]. Each activity needs a time slot. Overlapping means two activities share some time, which is not allowed.
Result
You can see which activities overlap by comparing their start and end times.
Knowing how to check if two activities overlap is the base for solving the problem.
2
FoundationSorting Activities by Finish Time
🤔
Concept: Sorting activities by their finishing times helps us pick the earliest finishing ones first.
Given activities, sort them so the one that ends earliest comes first. For example, [{start:1,end:2}, {start:3,end:4}, {start:0,end:6}] sorted by end time is [{start:1,end:2}, {start:3,end:4}, {start:0,end:6}].
Result
Sorted list lets us consider activities in order of finishing times.
Sorting by finish time is key because it helps us make the best choice at each step.
3
IntermediateGreedy Choice: Pick 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 current one ends. Repeat until no more activities fit.
Result
You get a list of activities that don't overlap and are as many as possible.
Understanding that picking earliest finishing activities maximizes total count is the heart of the greedy approach.
4
IntermediateImplementing the Selection Algorithm
🤔Before reading on: Do you think you need to check all activities every time, or can you skip some? Commit to your answer.
Concept: After picking an activity, you only check activities starting after it ends.
Loop through sorted activities. Keep track of the last selected activity's end time. If the next activity starts after this end time, select it.
Result
Efficiently selects maximum activities without overlap.
Knowing you can skip activities that start too early saves time and simplifies the code.
5
IntermediateDry Run with Example Activities
🤔
Concept: Walk through the algorithm step-by-step with a real example.
Activities: [{start:1,end:2}, {start:3,end:4}, {start:0,end:6}, {start:5,end:7}, {start:8,end:9}] Sorted by end time: [{start:1,end:2}, {start:3,end:4}, {start:0,end:6}, {start:5,end:7}, {start:8,end:9}] Select {start:1,end:2}, next start >= 2 is {start:3,end:4}, select it, next start >=4 is {start:5,end:7}, select it, next start >=7 is {start:8,end:9}, select it. Result: 4 activities selected.
Result
Selected activities: [{start:1,end:2}, {start:3,end:4}, {start:5,end:7}, {start:8,end:9}]
Seeing the algorithm in action clarifies how it picks the best combination.
6
AdvancedTime Complexity and Optimization
🤔Before reading on: Do you think sorting or selection takes more time? Commit to your answer.
Concept: Sorting takes O(n log n), selection takes O(n), total O(n log n).
Sorting activities by finish time is the most time-consuming step. The selection loop only goes through activities once. This makes the algorithm efficient for large inputs.
Result
Algorithm runs quickly even for many activities.
Understanding time complexity helps you predict performance and optimize code.
7
ExpertHandling Edge Cases and Variations
🤔Before reading on: Do you think activities that end exactly when another starts overlap? Commit to your answer.
Concept: Activities that end at the same time another starts do NOT overlap and can both be selected.
If activity A ends at time t and activity B starts at time t, both can be chosen. Also, variations include weighted activities or multiple resources, which need different approaches.
Result
Correct handling of edge cases ensures maximum activities are selected without errors.
Knowing subtle rules about overlaps prevents bugs and extends the algorithm to complex scenarios.
Under the Hood
The algorithm sorts activities by their finish times, then iterates once to select compatible activities. It uses a greedy strategy, always choosing the local best option (earliest finish) to build a global optimum solution. This works because once an activity finishes early, it leaves maximum room for others, and no better global solution can be found by skipping it.
Why designed this way?
This problem was designed to show how greedy algorithms can solve optimization problems efficiently. Alternatives like dynamic programming exist but are more complex and slower. The greedy approach was chosen for its simplicity and optimality in this specific problem.
Sorted Activities by finish time:
┌─────────────┐
│ Activity 1  │ Finish at 2
├─────────────┤
│ Activity 2  │ Finish at 4
├─────────────┤
│ Activity 3  │ Finish at 6
├─────────────┤
│ Activity 4  │ Finish at 7
├─────────────┤
│ Activity 5  │ Finish at 9
└─────────────┘

Selection process:
Start -> Select Activity 1
         ↓
Next activity starts after 2? Yes -> Select Activity 2
         ↓
Next activity starts after 4? Yes -> Select Activity 4
         ↓
Next activity starts after 7? Yes -> Select Activity 5
         ↓
End
Myth Busters - 3 Common Misconceptions
Quick: Do you think picking the longest activity first leads to the maximum number of activities? Commit to yes or no.
Common Belief:Choosing the longest activity first will maximize the total time used and thus the number of activities.
Tap to reveal reality
Reality:Picking the longest activity first often reduces the total number of activities you can attend because it blocks time for others.
Why it matters:Following this wrong belief causes fewer activities to be selected, wasting opportunities.
Quick: Do you think activities that end exactly when another starts overlap? Commit to yes or no.
Common Belief:If one activity ends at time t and another starts at time t, they overlap and cannot both be selected.
Tap to reveal reality
Reality:Activities that end at time t and start at time t do NOT overlap and both can be selected.
Why it matters:Misunderstanding this causes missing out on valid activities, reducing the solution's quality.
Quick: Do you think sorting by start time instead of finish time works equally well? Commit to yes or no.
Common Belief:Sorting activities by their start times is enough to select the maximum number of activities.
Tap to reveal reality
Reality:Sorting by start time does not guarantee the optimal solution; sorting by finish time is necessary.
Why it matters:Using the wrong sorting leads to suboptimal selections and fewer activities.
Expert Zone
1
The greedy choice property holds only because activities are sorted by finish time; changing sorting breaks optimality.
2
In weighted activity selection, where activities have values, greedy fails and dynamic programming is needed.
3
Handling activities with identical finish times requires careful tie-breaking to maintain correctness.
When NOT to use
Do not use this greedy approach when activities have weights or values; instead, use dynamic programming. Also, if multiple resources or rooms are involved, interval partitioning or coloring algorithms are better.
Production Patterns
Used in scheduling systems like calendar apps to maximize meeting room usage, in CPU task scheduling to maximize throughput, and in event planning software to avoid conflicts.
Connections
Greedy Algorithms
The Activity Selection Problem is a classic example of a greedy algorithm.
Understanding this problem helps grasp the greedy strategy of making locally optimal choices to achieve a global optimum.
Interval Scheduling
Activity Selection is a specific case of interval scheduling problems.
Knowing this problem aids in understanding more complex scheduling tasks involving multiple resources or constraints.
Resource Allocation in Operations Research
Both deal with assigning limited resources over time to maximize usage or profit.
Learning Activity Selection provides a foundation for understanding how to allocate resources efficiently in industries like manufacturing or logistics.
Common Pitfalls
#1Selecting activities without sorting by finish time.
Wrong approach:const activities = [{start:1,end:4},{start:3,end:5},{start:0,end:6}]; let selected = []; for(let i=0; i= selected[selected.length-1].end) { selected.push(activities[i]); } } console.log(selected);
Correct approach:const activities = [{start:1,end:4},{start:3,end:5},{start:0,end:6}]; activities.sort((a,b) => a.end - b.end); let selected = []; for(let i=0; i= selected[selected.length-1].end) { selected.push(activities[i]); } } console.log(selected);
Root cause:Not sorting by finish time breaks the greedy strategy, leading to suboptimal selections.
#2Treating activities that end and start at the same time as overlapping.
Wrong approach:if(activity.start > lastSelected.end) { select activity } // using > instead of >=
Correct approach:if(activity.start >= lastSelected.end) { select activity } // using >=
Root cause:Misunderstanding the definition of overlap causes missing valid activities.
#3Trying to pick the longest activity first.
Wrong approach:activities.sort((a,b) => (b.end - b.start) - (a.end - a.start)); // sort by duration descending // then select activities greedily
Correct approach:activities.sort((a,b) => a.end - b.end); // sort by finish time ascending // then select activities greedily
Root cause:Confusing longest duration with earliest finish time leads to fewer total activities.
Key Takeaways
The Activity Selection Problem teaches how to choose the maximum number of non-overlapping activities by always picking the earliest finishing one first.
Sorting activities by their finish times is essential to apply the greedy strategy correctly.
Activities that end exactly when another starts do not overlap and both can be selected.
Greedy algorithms work here because local optimal choices lead to a global optimum solution.
For weighted or more complex scheduling problems, different approaches like dynamic programming are needed.

Practice

(1/5)
1. What is the main goal of the Activity Selection Problem?
easy
A. Select the maximum number of activities that don't overlap in time
B. Find the activity with the longest duration
C. Sort activities by their start times
D. Calculate the total time of all activities

Solution

  1. Step 1: Understand the problem goal

    The Activity Selection Problem aims to choose the largest set of activities that do not overlap in their time intervals.
  2. Step 2: Clarify what is NOT the goal

    Finding the longest activity or sorting alone does not solve the problem; the focus is on maximizing non-overlapping activities.
  3. Final Answer:

    Select the maximum number of activities that don't overlap in time -> Option A
  4. Quick Check:

    Maximize non-overlapping activities = Select max activities [OK]
Hint: Focus on non-overlapping activities to maximize count [OK]
Common Mistakes:
  • Thinking it's about longest activity duration
  • Confusing sorting with selection
  • Trying to maximize total time instead of count
2. Which of the following is the correct way to sort activities by their finish time in JavaScript?
easy
A. activities.sort((a, b) => a.finish - b.finish);
B. activities.sort((a, b) => a.start - b.start);
C. activities.sort((a, b) => b.finish - a.finish);
D. activities.sort((a, b) => a.duration - b.duration);

Solution

  1. Step 1: Identify sorting key for Activity Selection

    We must sort activities by their finish time in ascending order to apply the greedy approach.
  2. Step 2: Choose correct JavaScript sort syntax

    The correct syntax is activities.sort((a, b) => a.finish - b.finish); which sorts by finish time ascending.
  3. Final Answer:

    activities.sort((a, b) => a.finish - b.finish); -> Option A
  4. Quick Check:

    Sort by finish time ascending = activities.sort((a, b) => a.finish - b.finish); [OK]
Hint: Sort activities by finish time ascending for greedy selection [OK]
Common Mistakes:
  • Sorting by start time instead of finish time
  • Sorting finish time descending
  • Sorting by duration which is irrelevant here
3. What will be the output of the following code snippet?
const activities = [
  {start: 1, finish: 4},
  {start: 3, finish: 5},
  {start: 0, finish: 6},
  {start: 5, finish: 7},
  {start: 8, finish: 9},
  {start: 5, finish: 9}
];

activities.sort((a, b) => a.finish - b.finish);

let count = 1;
let lastFinish = activities[0].finish;

for (let i = 1; i < activities.length; i++) {
  if (activities[i].start >= lastFinish) {
    count++;
    lastFinish = activities[i].finish;
  }
}
console.log(count);
medium
A. 6
B. 3
C. 5
D. 4

Solution

  1. Step 1: Sort activities by finish time

    Sorted activities by finish time ascending: [{start:1, finish:4}, {start:3, finish:5}, {start:0, finish:6}, {start:5, finish:7}, {start:8, finish:9}, {start:5, finish:9}].
  2. Step 2: Select activities greedily

    Start with first activity (finish=4). Next, select activities starting >=4: (start=5, finish=7), count=2; then (start=8, finish=9), count=3; then (start=9, finish=9) does not exist but next is (start=5, finish=9) which starts before 9, so skip. Total count is 4.
  3. Final Answer:

    4 -> Option D
  4. Quick Check:

    Greedy selection count = 4 [OK]
Hint: Sort by finish, pick next starting after last finish [OK]
Common Mistakes:
  • Not sorting activities before selection
  • Counting overlapping activities
  • Updating lastFinish incorrectly
4. Identify the bug in the following code for Activity Selection Problem:
function selectActivities(activities) {
  activities.sort((a, b) => a.start - b.start);
  let count = 1;
  let lastFinish = activities[0].finish;
  for (let i = 1; i < activities.length; i++) {
    if (activities[i].start > lastFinish) {
      count++;
      lastFinish = activities[i].finish;
    }
  }
  return count;
}
medium
A. Initialize count to 0 instead of 1
B. Comparison should be activities[i].start >= lastFinish
C. Sorting should be by finish time, not start time
D. No bug, code is correct

Solution

  1. Step 1: Check sorting criteria

    The greedy approach requires sorting activities by their finish time, but the code sorts by start time, which is incorrect.
  2. Step 2: Understand impact of wrong sorting

    Sorting by start time can cause wrong selection order, leading to suboptimal count of activities.
  3. Final Answer:

    Sorting should be by finish time, not start time -> Option C
  4. Quick Check:

    Sort by finish time for correct greedy selection [OK]
Hint: Always sort by finish time, not start time [OK]
Common Mistakes:
  • Sorting by start time instead of finish time
  • Using > instead of >= in condition (less critical)
  • Incorrect initialization of count
5. Given the activities with start and finish times:
const activities = [
  {start: 2, finish: 3},
  {start: 1, finish: 4},
  {start: 5, finish: 7},
  {start: 6, finish: 9},
  {start: 8, finish: 10},
  {start: 9, finish: 11}
];

What is the maximum number of non-overlapping activities that can be selected?
hard
A. 6
B. 4
C. 5
D. 3

Solution

  1. Step 1: Sort activities by finish time

    Sorted activities by finish time ascending: [{start:2, finish:3}, {start:1, finish:4}, {start:5, finish:7}, {start:6, finish:9}, {start:8, finish:10}, {start:9, finish:11}].
  2. Step 2: Select activities greedily

    Select (2,3), then (5,7), then (8,10), then (9,11) overlaps with (8,10) so skip; but (6,9) overlaps with (5,7) so skip. Total count is 4.
  3. Step 3: Check for more selections

    Others overlap and cannot be selected without violating non-overlap. Maximum count is 4.
  4. Final Answer:

    4 -> Option B
  5. Quick Check:

    Max non-overlapping activities = 4 [OK]
Hint: Sort by finish time, pick next starting after last finish [OK]
Common Mistakes:
  • Not sorting activities before selection
  • Selecting overlapping activities
  • Ignoring start time conditions
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard