From 0e35a7d77b4971efe64c14f568bb1fd3e9b453e4 Mon Sep 17 00:00:00 2001 From: spencerkrebs Date: Sun, 21 Jun 2026 21:17:50 -0400 Subject: [PATCH] v --- partition-labels.py | 46 ++++++++++++ task-scheduler.py | 167 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 partition-labels.py create mode 100644 task-scheduler.py diff --git a/partition-labels.py b/partition-labels.py new file mode 100644 index 0000000..a035bc8 --- /dev/null +++ b/partition-labels.py @@ -0,0 +1,46 @@ +class Solution: + def partitionLabels(self, s: str) -> List[int]: + # last positions + last = {} + for i,c in enumerate(s): + last[c]=i + # {c:i for i,c in enumerate(s)} + # {'a': 8, 'b': 5, 'c': 7, 'd': 14, 'e': 15, 'f': 11, 'g': 13, 'h': 19, 'i': 22, 'j': 23, 'k': 20, 'l': 21} + start = 0 #16 + end = 0 #23 + output = [] #9,7,8 + # end = 8 +# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + # "a b a b c b a c a d e f e g d e h i j h k l i j" + # i + for i,c in enumerate(s): + end = max(end,last[c]) + if i == end: + output.append(end-start+1) + start = i+1 + return output + + +# 3. Visualizing the Guarantee: "ababcc" +# Let's see why it's mathematically impossible for a letter to leak out, using the example s = "ababcc" where last = {'a': 2, 'b': 3, 'c': 5}. + +# i = 0, c = 'a': last['a'] is 2. end becomes max(0, 2) = 2. The partition must go to at least index 2. + +# i = 1, c = 'b': last['b'] is 3. end becomes max(2, 3) = 3. Because 'b' sneaked in, our boundary is forced to stretch further out to index 3. + +# i = 2, c = 'a': last['a'] is 2. end becomes max(3, 2) = 3. No expansion needed. + +# i = 3, c = 'b': last['b'] is 3. end becomes max(3, 3) = 3. + +# At this exact moment, i == end (3 == 3). + +# Why is this the perfect moment to snap the partition? +# Think about what it means when i finally catches up to end: + +# We have successfully examined every single character from start to i. + +# For every single one of those characters, we checked where its final duplicate lives. + +# None of them had a final duplicate living anywhere past index i (otherwise, end would have been pushed past i, and i == end wouldn't be true). + +# Because no character inside our current window has a twin waiting for it down the line, we can safely snap the partition shut knowing it is a completely isolated island. We log the size, reset start = i + 1, and begin building the next island. \ No newline at end of file diff --git a/task-scheduler.py b/task-scheduler.py new file mode 100644 index 0000000..8cd3abe --- /dev/null +++ b/task-scheduler.py @@ -0,0 +1,167 @@ +class Solution: + def leastInterval(self, tasks: List[str], n: int) -> int: + count = Counter(tasks) + # Counter({'A': 3, 'B': 3}) + maxHeap=[] + for cnt in count.values(): + maxHeap.append(-cnt) + # maxHeap = [-2,-3] + heapq.heapify(maxHeap) + time = 0 # 1 + q = collections.deque() + # q=[[-2,3]] + while maxHeap or q: + time += 1 + if maxHeap: + cnt = 1 + heapq.heappop(maxHeap) + # cnt = -2 + if cnt: + q.append([cnt,time+n]) + if q and q[0][1] == time: + heapq.heappush(maxHeap, q.popleft()[0]) + + return time + + + +--- SIMULATION START --- + +⏰ [Time = 1] Loop condition evaluated: 'while maxHeap or q' is TRUE because: + -> Elements in Heap? True (Frequencies: [3, 3]) + -> Elements in Queue? False (Queue: []) + + ❓ Checking condition: 'if maxHeap:' + ✅ TRUE: There is at least one task type available to run. + 👉 Action: Popped task from heap (had 3 remaining). It is now executing. + ❓ Checking sub-condition: 'if cnt:' (Are there more copies of this task left? New count = 2) + ✅ TRUE: 2 copies remain. Sending task to cooldown queue. + 👉 Calculation: Current Time (1) + Cooldown (2) = Available again at Time 3 + + ❓ Checking condition: 'if q and q[0][1] == time:' + ... Queue has items. Checking if the front task's ready time (3) matches Current Time (1)... + ❌ FALSE: The front task isn't ready yet. It needs to wait until Time = 3. + + 📊 End of Tick 1 Status -> Heap: [3] | Queue: [[2, 3]] +------------------------------------------------------------ + +⏰ [Time = 2] Loop condition evaluated: 'while maxHeap or q' is TRUE because: + -> Elements in Heap? True (Frequencies: [3]) + -> Elements in Queue? True (Queue: [[2, 3]]) + + ❓ Checking condition: 'if maxHeap:' + ✅ TRUE: There is at least one task type available to run. + 👉 Action: Popped task from heap (had 3 remaining). It is now executing. + ❓ Checking sub-condition: 'if cnt:' (Are there more copies of this task left? New count = 2) + ✅ TRUE: 2 copies remain. Sending task to cooldown queue. + 👉 Calculation: Current Time (2) + Cooldown (2) = Available again at Time 4 + + ❓ Checking condition: 'if q and q[0][1] == time:' + ... Queue has items. Checking if the front task's ready time (3) matches Current Time (2)... + ❌ FALSE: The front task isn't ready yet. It needs to wait until Time = 3. + + 📊 End of Tick 2 Status -> Heap: [] | Queue: [[2, 3], [2, 4]] +------------------------------------------------------------ + +⏰ [Time = 3] Loop condition evaluated: 'while maxHeap or q' is TRUE because: + -> Elements in Heap? False (Frequencies: []) + -> Elements in Queue? True (Queue: [[2, 3], [2, 4]]) + + ❓ Checking condition: 'if maxHeap:' + ❌ FALSE: The heap is completely empty. The CPU has no choice but to sit IDLE this turn. + + ❓ Checking condition: 'if q and q[0][1] == time:' + ... Queue has items. Checking if the front task's ready time (3) matches Current Time (3)... + ✅ TRUE: The task at the front of the queue has finished its cooldown! + 👉 Action: Popping from Queue and pushing 2 copies back into the Max Heap. + + 📊 End of Tick 3 Status -> Heap: [2] | Queue: [[2, 4]] +------------------------------------------------------------ + +⏰ [Time = 4] Loop condition evaluated: 'while maxHeap or q' is TRUE because: + -> Elements in Heap? True (Frequencies: [2]) + -> Elements in Queue? True (Queue: [[2, 4]]) + + ❓ Checking condition: 'if maxHeap:' + ✅ TRUE: There is at least one task type available to run. + 👉 Action: Popped task from heap (had 2 remaining). It is now executing. + ❓ Checking sub-condition: 'if cnt:' (Are there more copies of this task left? New count = 1) + ✅ TRUE: 1 copies remain. Sending task to cooldown queue. + 👉 Calculation: Current Time (4) + Cooldown (2) = Available again at Time 6 + + ❓ Checking condition: 'if q and q[0][1] == time:' + ... Queue has items. Checking if the front task's ready time (4) matches Current Time (4)... + ✅ TRUE: The task at the front of the queue has finished its cooldown! + 👉 Action: Popping from Queue and pushing 2 copies back into the Max Heap. + + 📊 End of Tick 4 Status -> Heap: [2] | Queue: [[1, 6]] +------------------------------------------------------------ + +⏰ [Time = 5] Loop condition evaluated: 'while maxHeap or q' is TRUE because: + -> Elements in Heap? True (Frequencies: [2]) + -> Elements in Queue? True (Queue: [[1, 6]]) + + ❓ Checking condition: 'if maxHeap:' + ✅ TRUE: There is at least one task type available to run. + 👉 Action: Popped task from heap (had 2 remaining). It is now executing. + ❓ Checking sub-condition: 'if cnt:' (Are there more copies of this task left? New count = 1) + ✅ TRUE: 1 copies remain. Sending task to cooldown queue. + 👉 Calculation: Current Time (5) + Cooldown (2) = Available again at Time 7 + + ❓ Checking condition: 'if q and q[0][1] == time:' + ... Queue has items. Checking if the front task's ready time (6) matches Current Time (5)... + ❌ FALSE: The front task isn't ready yet. It needs to wait until Time = 6. + + 📊 End of Tick 5 Status -> Heap: [] | Queue: [[1, 6], [1, 7]] +------------------------------------------------------------ + +⏰ [Time = 6] Loop condition evaluated: 'while maxHeap or q' is TRUE because: + -> Elements in Heap? False (Frequencies: []) + -> Elements in Queue? True (Queue: [[1, 6], [1, 7]]) + + ❓ Checking condition: 'if maxHeap:' + ❌ FALSE: The heap is completely empty. The CPU has no choice but to sit IDLE this turn. + + ❓ Checking condition: 'if q and q[0][1] == time:' + ... Queue has items. Checking if the front task's ready time (6) matches Current Time (6)... + ✅ TRUE: The task at the front of the queue has finished its cooldown! + 👉 Action: Popping from Queue and pushing 1 copies back into the Max Heap. + + 📊 End of Tick 6 Status -> Heap: [1] | Queue: [[1, 7]] +------------------------------------------------------------ + +⏰ [Time = 7] Loop condition evaluated: 'while maxHeap or q' is TRUE because: + -> Elements in Heap? True (Frequencies: [1]) + -> Elements in Queue? True (Queue: [[1, 7]]) + + ❓ Checking condition: 'if maxHeap:' + ✅ TRUE: There is at least one task type available to run. + 👉 Action: Popped task from heap (had 1 remaining). It is now executing. + ❓ Checking sub-condition: 'if cnt:' (Are there more copies of this task left? New count = 0) + ❌ FALSE: That was the absolute last copy of this task type. It is completely finished! + + ❓ Checking condition: 'if q and q[0][1] == time:' + ... Queue has items. Checking if the front task's ready time (7) matches Current Time (7)... + ✅ TRUE: The task at the front of the queue has finished its cooldown! + 👉 Action: Popping from Queue and pushing 1 copies back into the Max Heap. + + 📊 End of Tick 7 Status -> Heap: [1] | Queue: [] +------------------------------------------------------------ + +⏰ [Time = 8] Loop condition evaluated: 'while maxHeap or q' is TRUE because: + -> Elements in Heap? True (Frequencies: [1]) + -> Elements in Queue? False (Queue: []) + + ❓ Checking condition: 'if maxHeap:' + ✅ TRUE: There is at least one task type available to run. + 👉 Action: Popped task from heap (had 1 remaining). It is now executing. + ❓ Checking sub-condition: 'if cnt:' (Are there more copies of this task left? New count = 0) + ❌ FALSE: That was the absolute last copy of this task type. It is completely finished! + + ❓ Checking condition: 'if q and q[0][1] == time:' + ❌ FALSE: The cooldown queue is completely empty. Nothing to bring back. + + 📊 End of Tick 8 Status -> Heap: [] | Queue: [] +------------------------------------------------------------ + +--- SIMULATION END --- +Total Time Required: 8 \ No newline at end of file