|
1 | 1 | # [Problem 664: Strange Printer](https://leetcode.com/problems/strange-printer/description/?envType=daily-question)
|
2 | 2 |
|
3 | 3 | ## Initial thoughts (stream-of-consciousness)
|
| 4 | +- Ugh, *another* dynamic programming problem!? I hope this sequence ends soon 😱 |
| 5 | +- Ok, so how can we solve this one... 🤔 |
| 6 | + - First we can do some housekeeping by removing any repeated characters. This will take $O(n)$ time, which is "free" since the full algorithm will almost certainly by slower than that: |
| 7 | + ```python |
| 8 | + def simplify(s): |
| 9 | + x = s[0] |
| 10 | + for c in s[1:]: |
| 11 | + if c != x[-1]: |
| 12 | + x += c |
| 13 | + return x |
| 14 | + ``` |
| 15 | + - Next, we should define a helper function: |
| 16 | + - Take in...what? Maybe a start index and end index for a substring of the (simplified) `s`? We could also pass in a substring directly, but that'd require copying the substrings in memory (inefficient). Since nothing will get modified, I think we can just reference using indices. |
| 17 | + - The helper function should return the turns required for that substring |
| 18 | + - To figure out: how will this work? |
| 19 | + - Then the function will be something like |
| 20 | + ```python |
| 21 | + s = simplify(s) |
| 22 | + return helper(0, len(s) - 1) |
| 23 | + ``` |
| 24 | +- I'm guessing `helper` will end up calling the same indices multiple times recursively, so we should also cache the results to avoid re-computing them: |
| 25 | +```python |
| 26 | +cache = {} |
| 27 | +def helper(a, b): |
| 28 | + if (a, b) in cache: |
| 29 | + return cache[(a, b)] |
| 30 | + |
| 31 | + turns = <do computations, probably call helper recursively> |
| 32 | + cache[(a, b)] = turns |
| 33 | + return turns |
| 34 | +``` |
| 35 | +- So the "trick" here will be figuring out how that `helper` function should look. |
4 | 36 |
|
5 | 37 | ## Refining the problem, round 2 thoughts
|
| 38 | +- If the substring is empty, return 0. This happens if `a > b`. |
| 39 | +- If the substring is just a single character, return 1 (`a == b`) |
| 40 | +- We'll need to iteratively improve on the number of turns. The worst case would be `b - a + 1` (i.e., one turn per character). |
| 41 | + - If there are duplicated characters (since we've already simplified, these will be separated by intervening characters), we can improve on this worst case. So we'll need to detect duplicates. |
| 42 | + - We could start at the first character, and see if there are any duplicates of *that* character. If we find a duplicate (say the first one occurs at position `j`) then we can save one turn (print the duplicate character, then figure out how many turns are needed for `s[a + 1:j]`. So the total for that sub-sequence would be `1 + helper(a, j - 1)`. Then we can skip over character `j`. Then we need to compute the number of turns needed for `s[j + 1:b]`. We can update `min_turns = min(min_turns, helper(a, j - 1) + helper(j + 1, b))` |
| 43 | + - If we find *another* duplicate later on in the sequence, we can just repeat this process. But the cache will avoid re-computing things many times. |
| 44 | +- Let's try this...it might not be too bad. I might be missing something, but I'm surprised this is a "hard" problem; the recent "medium" problems have seemed trickier! |
6 | 45 |
|
7 | 46 | ## Attempted solution(s)
|
8 | 47 | ```python
|
9 |
| -class Solution: # paste your code here! |
10 |
| - ... |
| 48 | +class Solution: |
| 49 | + def strangePrinter(self, s: str) -> int: |
| 50 | + def simplify(s): |
| 51 | + x = s[0] |
| 52 | + for c in s[1:]: |
| 53 | + if c != x[-1]: |
| 54 | + x += c |
| 55 | + return x |
| 56 | + |
| 57 | + s = simplify(s) |
| 58 | + cache = {} |
| 59 | + def helper(a, b): |
| 60 | + if a > b: |
| 61 | + return 0 |
| 62 | + elif a == b: |
| 63 | + return 1 |
| 64 | + elif (a, b) in cache: |
| 65 | + return cache[(a, b)] |
| 66 | + |
| 67 | + min_turns = b - a + 1 |
| 68 | + for i in range(a + 1, b + 1): |
| 69 | + if s[a] == s[i]: |
| 70 | + min_turns = min(min_turns, helper(a, i - 1) + helper(i + 1, b)) |
| 71 | + cache[(a, b)] = min_turns |
| 72 | + return min_turns |
| 73 | + |
| 74 | + return helper(0, len(s) - 1) |
11 | 75 | ```
|
| 76 | +- Given test cases pass |
| 77 | +- Let's try some longer strings: |
| 78 | + - `s = "abaabababaabababababbbabababacccbbcbcbabaababa"`: pass(!!) |
| 79 | + - `s = "ddzdmpdnrmndphslxhewdhrnwlmlinkpttuopysqgvhssxqxiozhffyxwvyfcwhkpxxcmxzxvodtjsiiuzzmxveddcvtuhxanzgb": womp womp...fail 😞 |
| 80 | + - Ok...let's brainstorm...I think there are a few possible things that could be happening: |
| 81 | + - Most likely: the logic of just checking for the first matching character might not make sense. How do we match other characters? |
| 82 | + - Actually, maybe we should initialize `min_turns` to `1 + helper(a + 1, b)`. That way each recursive call will consider matches of the "new `a`" in turn. I wonder if that will just fix the problem "for free." |
| 83 | +```python |
| 84 | +class Solution: |
| 85 | + def strangePrinter(self, s: str) -> int: |
| 86 | + def simplify(s): |
| 87 | + x = s[0] |
| 88 | + for c in s[1:]: |
| 89 | + if c != x[-1]: |
| 90 | + x += c |
| 91 | + return x |
| 92 | + |
| 93 | + s = simplify(s) |
| 94 | + cache = {} |
| 95 | + def helper(a, b): |
| 96 | + if a > b: |
| 97 | + return 0 |
| 98 | + elif a == b: |
| 99 | + return 1 |
| 100 | + elif (a, b) in cache: |
| 101 | + return cache[(a, b)] |
| 102 | + |
| 103 | + min_turns = 1 + helper(a + 1, b) |
| 104 | + for i in range(a + 1, b + 1): |
| 105 | + if s[a] == s[i]: |
| 106 | + min_turns = min(min_turns, helper(a, i - 1) + helper(i + 1, b)) |
| 107 | + cache[(a, b)] = min_turns |
| 108 | + return min_turns |
| 109 | + |
| 110 | + return helper(0, len(s) - 1) |
| 111 | +``` |
| 112 | +- That fixes the above test cases! Let's try some more... |
| 113 | +- `s = "niqmxxbwvonppouiypidwbqmodqvtnlaxxdgpayhmzywnyojfkqobatdyhfkzayazifwqyfpgxlpbupyascdfnqtnmrdlwwkagiq": pass |
| 114 | +- `s = "naajdcjcrvbhmjxgkenbqdkikmnxufughnjwasclwuvrenhksnosyigmnovmexmegklcqllfmxbbhtvazzcqhltoiukvsvgnwyvl": pass |
| 115 | +- What about some silly cases? |
| 116 | + - `s = "aaaaaaaaaaa": pass |
| 117 | +- Ok, let's try submitting... |
| 118 | + |
| 119 | + |
| 120 | + |
| 121 | +Solved! |
| 122 | + |
0 commit comments