Optimise 2024.07
This commit is contained in:
parent
b2fa4b72b6
commit
82ffa429d7
5 changed files with 50 additions and 46 deletions
|
@ -3,7 +3,7 @@
|
|||
Part 1 is:
|
||||
* greater than 450054910499
|
||||
|
||||
Before optimisation (pregenerating then testing operator combiantions using `itertools.product("*+|", length=n)`), runtime looks something like this:
|
||||
Before optimisation (pregenerating then testing operator combiantions using `itertools.product("*+|", length=n)`), run time looks something like this:
|
||||
|
||||
```
|
||||
Part 1: min 0.2671 seconds, max 0.2818 seconds, avg 0.2755
|
||||
|
@ -12,3 +12,11 @@ Part 2: min 23.2387 seconds, max 24.8753 seconds, avg 23.8805
|
|||
|
||||
It also appeared that using string concatenation as opposed to pure mathematical functions for the concatenation operator was marginally faster in Python.
|
||||
|
||||
After optimisation (recursive solves working backwards through the numbers), the run time looks something like this:
|
||||
|
||||
```
|
||||
Part 1: min 0.0214 seconds, max 0.041 seconds, avg 0.0233
|
||||
Part 2: min 0.0215 seconds, max 0.0273 seconds, avg 0.0229
|
||||
```
|
||||
|
||||
The intial version of this solve is in commit `b2fa4b7`.
|
|
@ -14,58 +14,51 @@ def parse(instr: str) -> list[tuple[int, list[int]]]:
|
|||
return res
|
||||
|
||||
|
||||
def evaluate(ns: list[int], ops: Iterable[str]):
|
||||
acc = ns[0]
|
||||
for i, (v, op) in enumerate(zip(ns[1:], ops)):
|
||||
if op == "*":
|
||||
acc *= v
|
||||
elif op == "+":
|
||||
acc += v
|
||||
elif op == "|":
|
||||
acc = (acc * (10 ** int(math.log10(v) + 1))) + v
|
||||
else:
|
||||
raise ValueError(f"unknown operation {op}")
|
||||
return acc
|
||||
def ends_with(x: int, y: int) -> bool:
|
||||
ycard = int(math.log10(y)) + 1
|
||||
return (x - y) * (10**-ycard) == int(x * (10**-ycard))
|
||||
|
||||
|
||||
def trim_int(x: int, y: int) -> int:
|
||||
ycard = int(math.log10(y)) + 1
|
||||
return int((x - y) * (10**-ycard))
|
||||
|
||||
|
||||
def solve(target: int, ns: list[int], use_concat: bool = False) -> bool:
|
||||
v = ns[-1]
|
||||
rest = ns[:-1]
|
||||
|
||||
if len(rest) == 0:
|
||||
return target == v
|
||||
|
||||
if target % v == 0:
|
||||
# this represents a possible multiplication
|
||||
if solve(int(target / v), rest, use_concat):
|
||||
return True
|
||||
|
||||
if use_concat and ends_with(target, v):
|
||||
# this is a possible concatenation
|
||||
if solve(trim_int(target, v), rest, use_concat):
|
||||
return True
|
||||
|
||||
# last resort, addition
|
||||
return solve(target - v, rest, use_concat)
|
||||
|
||||
|
||||
def one(instr: str):
|
||||
cases = parse(instr)
|
||||
|
||||
cached_ops = {}
|
||||
|
||||
n = 0
|
||||
for (target, numbers) in cases:
|
||||
num_ops = len(numbers) - 1
|
||||
if num_ops not in cached_ops:
|
||||
cached_ops[num_ops] = tuple(itertools.product("+*", repeat=num_ops))
|
||||
|
||||
for ops in cached_ops[num_ops]:
|
||||
v = evaluate(numbers, ops)
|
||||
if v == target:
|
||||
n += v
|
||||
break
|
||||
|
||||
return n
|
||||
return itertools.accumulate(
|
||||
target if solve(target, numbers, use_concat=False) else 0
|
||||
for (target, numbers) in cases
|
||||
)
|
||||
|
||||
|
||||
def two(instr: str):
|
||||
cases = parse(instr)
|
||||
|
||||
cached_ops = {}
|
||||
|
||||
n = 0
|
||||
for (target, numbers) in cases:
|
||||
num_ops = len(numbers) - 1
|
||||
if num_ops not in cached_ops:
|
||||
cached_ops[num_ops] = tuple(itertools.product("+*|", repeat=num_ops))
|
||||
|
||||
for ops in cached_ops[num_ops]:
|
||||
v = evaluate(numbers, ops)
|
||||
if v == target:
|
||||
n += v
|
||||
break
|
||||
|
||||
return n
|
||||
return itertools.accumulate(
|
||||
target if solve(target, numbers, use_concat=True) else 0
|
||||
for (target, numbers) in cases
|
||||
)
|
||||
|
||||
|
||||
def _debug(*args, **kwargs):
|
||||
|
|
|
@ -19,4 +19,5 @@ A day denoted with an asterisk means it has a visualisation.
|
|||
| 03 - Mull It Over | ★ ★ | Python | The first instance of Advent of Parsing this year! |
|
||||
| 04* - Ceres Search | ★ ★ | Python | When it says a cross, it does not mean a plus. |
|
||||
| 05 - Print Queue | ★ ★ | Python | Before you dismiss and idea as being "too simple", make sure you check that it doesn't work. |
|
||||
| 06 - Guard Gallivant | ★ ★ | Python | oh dear runtime (also I knew what I wanted to do for so long it just took me 3 hours to implement it properly) |
|
||||
| 06 - Guard Gallivant | ★ ★ | Python | oh dear runtime (also I knew what I wanted to do for so long it just took me 3 hours to implement it properly) |
|
||||
| 07 - Bridge Repair | ★ ★ | Python | Maths? Backwards?? |
|
Binary file not shown.
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 46 KiB |
|
@ -12,3 +12,5 @@
|
|||
{"day": 6, "part": 2, "runner": "py", "min": 15.881408452987671, "max": 17.086341857910156, "avg": 16.64130985736847, "n": 6}
|
||||
{"day": 7, "part": 1, "runner": "py", "min": 0.26709485054016113, "max": 0.28178858757019043, "avg": 0.2754525661468506, "n": 5}
|
||||
{"day": 7, "part": 2, "runner": "py", "min": 23.23872661590576, "max": 24.87530255317688, "avg": 23.880544805526732, "n": 5}
|
||||
{"day": 7, "part": 1, "runner": "py", "min": 0.02138209342956543, "max": 0.04097461700439453, "avg": 0.023260540962219238, "n": 100}
|
||||
{"day": 7, "part": 2, "runner": "py", "min": 0.021509647369384766, "max": 0.027263402938842773, "avg": 0.022869422435760497, "n": 100}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue