<p>There is a computer that can run an unlimited number of tasks <strong>at the same time</strong>. You are given a 2D integer array <code>tasks</code> where <code>tasks[i] = [start<sub>i</sub>, end<sub>i</sub>, duration<sub>i</sub>]</code> indicates that the <code>i<sup>th</sup></code> task should run for a total of <code>duration<sub>i</sub></code> seconds (not necessarily continuous) within the <strong>inclusive</strong> time range <code>[start<sub>i</sub>, end<sub>i</sub>]</code>.</p>

<p>You may turn on the computer only when it needs to run a task. You can also turn it off if it is idle.</p>

<p>Return <em>the minimum time during which the computer should be turned on to complete all tasks</em>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> tasks = [[2,3,1],[4,5,1],[1,5,2]]
<strong>Output:</strong> 2
<strong>Explanation:</strong> 
- The first task can be run in the inclusive time range [2, 2].
- The second task can be run in the inclusive time range [5, 5].
- The third task can be run in the two inclusive time ranges [2, 2] and [5, 5].
The computer will be on for a total of 2 seconds.
</pre>

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

<pre>
<strong>Input:</strong> tasks = [[1,3,2],[2,5,3],[5,6,2]]
<strong>Output:</strong> 4
<strong>Explanation:</strong> 
- The first task can be run in the inclusive time range [2, 3].
- The second task can be run in the inclusive time ranges [2, 3] and [5, 5].
- The third task can be run in the two inclusive time range [5, 6].
The computer will be on for a total of 4 seconds.
</pre>

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

<ul>
	<li><code>1 &lt;= tasks.length &lt;= 2000</code></li>
	<li><code>tasks[i].length == 3</code></li>
	<li><code>1 &lt;= start<sub>i</sub>, end<sub>i</sub> &lt;= 2000</code></li>
	<li><code>1 &lt;= duration<sub>i</sub> &lt;= end<sub>i</sub> - start<sub>i</sub> + 1 </code></li>
</ul>

class Solution(object):
    def findMinimumTime(self, tasks: List[List[int]]) -> int: 
        
        # We can quickly check if a task overlaps with previous tasks if the tasks are ordered based on the ending time
        tasks.sort(key=lambda x : x[1])
        
        # Set to keep track of points where tasks has been ran already
        alreadyRan = set()
        
        # Go through each task
        for task in tasks:
            # If the values in this range [start,end] are already in set
            # It means, some previous task has ran in those time points
            # So we can run current tasks at the same time
            for i in range(task[0], task[1] + 1): 
                
                # We can reduce the duration as the current task runs in same time as some previous task
                if i in alreadyRan: task[2] -= 1
        
            # At this point, if the duration is still not 0
            # It means, we have to run this task at the rightmost time points in the range [start, end]
            if task[2] > 0:
                
                # We will run this task at the very end of this task's time range
                for i in range(task[1], task[0] - 1, -1):
                    # If at this time point, we have already ran this current task
                    # We cannot run it again at the same point
                    # THIS THING RESULTED IN SOME TEST CASES FAILING -_-
                    if i in alreadyRan: continue
                    
                    # We run the task at the current point
                    task[2] -= 1
                    
                    # Put the current time point in the set
                    alreadyRan.add(i)
                
                    # If duration becomes 0, break
                    if task[2] == 0: break
                        
        # Finally, we can simply return the length of the set
        # That is, all the time points at which we ran the tasks
        return len(alreadyRan)
973