<p>You are given an array of <code>events</code> where <code>events[i] = [startDay<sub>i</sub>, endDay<sub>i</sub>]</code>. Every event <code>i</code> starts at <code>startDay<sub>i</sub></code><sub> </sub>and ends at <code>endDay<sub>i</sub></code>.</p>

<p>You can attend an event <code>i</code> at any day <code>d</code> where <code>startTime<sub>i</sub> &lt;= d &lt;= endTime<sub>i</sub></code>. You can only attend one event at any time <code>d</code>.</p>

<p>Return <em>the maximum number of events you can attend</em>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2020/02/05/e1.png" style="width: 400px; height: 267px;" />
<pre>
<strong>Input:</strong> events = [[1,2],[2,3],[3,4]]
<strong>Output:</strong> 3
<strong>Explanation:</strong> You can attend all the three events.
One way to attend them all is as shown.
Attend the first event on day 1.
Attend the second event on day 2.
Attend the third event on day 3.
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> events= [[1,2],[2,3],[3,4],[1,2]]
<strong>Output:</strong> 4
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= events.length &lt;= 10<sup>5</sup></code></li>
	<li><code>events[i].length == 2</code></li>
	<li><code>1 &lt;= startDay<sub>i</sub> &lt;= endDay<sub>i</sub> &lt;= 10<sup>5</sup></code></li>
</ul>

import heapq

class Solution:
    def maxEvents(self, events: List[List[int]]) -> int:
        N = len(events)
        
        # Step 1: Sort events by start day first, then by end day if start days are the same.
        # Sorting helps in processing events in the order they can start.
        events.sort(key=lambda x: (x[0], x[1]))
        
        # Step 2: Determine the maximum day (last possible day an event can end).
        # This ensures we don't iterate over unnecessary days.
        days = 0
        for i in range(N):
            days = max(days, events[i][1])

        # Min-heap to store the end days of the events. ( min end days are prioritized)
        # We'll always attend the event that ends the earliest.
        event_heap = []
        
        # Index to keep track of which events we have processed (sorted by start date).
        event_idx = 0
        
        # Count the total number of events attended.
        total_events = 0

        # Step 3: Iterate through each day from 1 to the last possible day (`days`).
        for day in range(1, days + 1):
            # Step 4: For each day, add all events that start on this day to the heap.
            while event_idx < N and events[event_idx][0] == day:
                # Push the end day of the event to the min-heap.
                heapq.heappush(event_heap, events[event_idx][1])
                event_idx += 1
            
            # Step 5: Remove all events from the heap that have already expired (i.e., events that ended before today).
            while event_heap and event_heap[0] < day:
                heapq.heappop(event_heap)
            
            # Step 6: If there are any events available to attend today, attend the event that ends the earliest.
            if event_heap:
                # Attend the event by popping it from the heap (it means we use this event for today).
                heapq.heappop(event_heap)
                total_events += 1  # Increment the count of attended events.

        # Step 7: Return the total number of events attended.
        return total_events

65200