-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from paxtonfitzpatrick/main
solutions and notes for problems 1518 and 1550
- Loading branch information
Showing
2 changed files
with
108 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# [Problem 1518: Water Bottles](https://leetcode.com/problems/water-bottles) | ||
|
||
## Initial thoughts (stream-of-consciousness) | ||
|
||
- seems pretty simple... | ||
- when exchanging empties for fulls, will need to use floor division to figure out how many fulls we can get and also modulo to figure out how many empties couldn't be echanged | ||
- also need to keep track of unexchanged empties in case we can accumulate enough for another full (`numExchange`) | ||
- stop when we have no more fulls and not enough empties to exchange for a full | ||
- I think I'll structure this as a `while` loop where each time through the loop we can drink fulls and/or exchange empties | ||
- There's probably a more efficient way to do this without looping, where we calculate everything from the initial values (so, $O(1)$), but this seems like an easier place to start. | ||
- I bet there's also a way to set this up recursively, which could be interesting, but unlikely to be optimal | ||
|
||
## Refining the problem, round 2 thoughts | ||
|
||
- Version 2: I noticed some small tweaks I could make to the logic that I think would speed up the `while` loop version slightly | ||
- note: key to not having to modify `n_empties` twice each iteration is updating `n_fulls` and `n_empties` simultaneously. New values for both variables depend on the old value of the other, so updating both on the same line ensures both calculations use the "old" values. Could also have stored `n_empties + n_fulls` in a temporary variable, but that would've taken a teeny bit more time & memory. | ||
|
||
## Attempted solution(s) | ||
|
||
Version 1: | ||
|
||
```python | ||
class Solution: | ||
def numWaterBottles(self, numBottles: int, numExchange: int) -> int: | ||
n_fulls = numBottles | ||
n_empties = 0 | ||
n_drank = 0 | ||
while True: | ||
n_drank += n_fulls | ||
n_empties += n_fulls | ||
if n_empties < numExchange: | ||
return n_drank | ||
n_fulls = n_empties // numExchange | ||
n_empties = n_empties % numExchange | ||
``` | ||
|
||
![Version 1 results](https://github.com/paxtonfitzpatrick/leetcode-solutions/assets/26118297/08d502ae-a947-49fc-89a9-fb578ea937a6) | ||
|
||
Version 2: | ||
|
||
```python | ||
class Solution: | ||
def numWaterBottles(self, numBottles: int, numExchange: int) -> int: | ||
n_drank = numBottles | ||
n_fulls = numBottles // numExchange | ||
n_empties = numBottles % numExchange | ||
while n_fulls > 0: | ||
n_drank += n_fulls | ||
n_fulls, n_empties = (n_empties + n_fulls) // numExchange, (n_empties + n_fulls) % numExchange | ||
return n_drank | ||
``` | ||
|
||
![Version 2 results](https://github.com/paxtonfitzpatrick/leetcode-solutions/assets/26118297/ba0ca272-8761-4cc5-9c2f-9deb12d40361) | ||
Appears to be slower than version 1, but probably just due to random variation runtime of the test cases. Pretty confident that in reality, version 2 is marginally faster. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# [Problem 1550: Three Consecutive Odds](https://leetcode.com/problems/three-consecutive-odds/description/) | ||
|
||
## Initial thoughts (stream-of-consciousness) | ||
|
||
- seems like a pretty easy one | ||
- need to track the number of consecutive odds | ||
- if counter ever reaches 3, return True | ||
- if we encounter an even number, reset counter to 0 | ||
|
||
## Refining the problem | ||
|
||
- I bet this will ultimately be slower, but I can think of a kinda fun, roundabout way solve this: | ||
- convert `arr` to a string | ||
- use regular expression to search for 3 consecutive occurrences of values that end in 1, 3, 5, 7, or 9, separated by a command and space | ||
- we know that all values are <= 1000, and 1000 is an even number, so all odd numbers will have 1, 2, or 3 digits -- so for each number we need to match 0, 1, or 2 digits of any value, followed by an odd digit: `[0-9]{0,2}[13579]` | ||
- base pattern would be `(?:[0-9]{0,2}[13579], ){3}` but: | ||
- this would fail for the last 3 values in the list because there's no trailing comma. So instead use `(?:[0-9]{0,2}[13579], ){2}[0-9]{0,2}[13579]` | ||
- Also for the first of the 3 odd numbers, we should only try to match the final digit rather than all digits, otherwise the search will be slower because the pattern will initially match all values in the list and waste a bunch of time backtracking. So instead use `[13579], [0-9]{0,2}[13579], [0-9]{0,2}[13579]` or `[13579](?:, [0-9]{0,2}[13579]){2}` | ||
|
||
- `re.search` returns a `Match` object as soon as it encounters the first match, and `None` if no match is found. So we should be able to just `bool()` the result and return it. | ||
- I wonder if compiling the pattern upfront would be faster than using using the module-level functions... depends on how leetcode runs the test cases, I guess. If I compile the expression in the class body outside the method definition, and all test case runs reuse the same instance of the class, then it should save time. Otherwise, it probably wouldn't. Maybe I'll just compile it in the global namespace and see. | ||
|
||
## Attempted solution(s) | ||
|
||
```python | ||
class Solution: | ||
def threeConsecutiveOdds(self, arr: List[int]) -> bool: | ||
if len(arr) < 3: | ||
return False | ||
|
||
consec_odds = 0 | ||
for val in arr: | ||
if val % 2: | ||
if consec_odds == 2: | ||
return True | ||
consec_odds += 1 | ||
else: | ||
consec_odds = 0 | ||
return False | ||
``` | ||
|
||
![](https://github.com/paxtonfitzpatrick/leetcode-solutions/assets/26118297/c45d108c-b23b-48d8-bc14-13a2cdc0cc06) | ||
|
||
```python | ||
from re import compile | ||
|
||
pattern = compile(r"[13579](?:, [0-9]{0,2}[13579]){2}") | ||
|
||
class Solution: | ||
def threeConsecutiveOdds(self, arr: List[int]) -> bool: | ||
return bool(pattern.search(str(arr))) | ||
``` | ||
|
||
![](https://github.com/paxtonfitzpatrick/leetcode-solutions/assets/26118297/88d07bb2-f252-4797-81e4-33793acaeae4) |