I thought about it for 15 mins, but couldn’t think of any mathematical tricks. I thought of lots of minor tricks, like comparing the number to the result and not adding any more multiplications if it’s over, things that would cut 10%-20% here and there, but nothing which fundamentally changes big O running time.

For reference, here’s my solution for part 2 in smalltalk. I just generated every possible permutation and tested it. Part 1 is similar, mainly I just used bit magic to avoid generating permutations.

(even if you haven’t used it, smalltalk is fairly readable, everything is left to right, except in parens)

day7p2: in
	| input | 
	
	input := in lines collect: [ :l | (l splitOn: '\:|\s' asRegex) reject: #isEmpty thenCollect: #asInteger ].
	
	^ (input select: [ :line |
		(#(1 2 3) permutationsWithRepetitionsOfSize: line size - 2) 
			anySatisfy: [ :num | (self d7addmulcat: line ops: num) = (line at: 1)]
	]) sum: #first.
d7addmulcat: nums ops: ops
	| final |
	
	final := nums at: 2.
	ops withIndexDo: [ :op :i |
		op = 1 ifTrue: [ final := final * (nums at: i + 2) ].
		op = 2 ifTrue: [ final := final + (nums at: i + 2) ].
		op = 3 ifTrue: [ final := (final asString, (nums at: i+2) asString) asInteger ]
	].

	^ final
  • lwhjp@lemmy.sdf.org
    link
    fedilink
    arrow-up
    3
    ·
    1 day ago

    Probably the easiest optimization (which admittedly I didn’t think of myself) is to work backwards: you can eliminate multiplication and concatenation early if you start with the answer and check terms from the right.

    • morrowind@lemmy.mlOP
      link
      fedilink
      arrow-up
      1
      ·
      1 day ago

      I don’t entirely see how, you still need every possible combination of the left side to see what they would become. Plus addition and multiplication are order independent anyway

      • lwhjp@lemmy.sdf.org
        link
        fedilink
        arrow-up
        1
        ·
        1 day ago

        The point is to prune away search space as early as possible. If the rightmost operand is 5, say, and the answer ends in a 7, then the rightmost operator cannot be anything other than plus. This is a deduction you can’t make going left to right. Remember that in this problem the usual order of operations does not apply.

        • Katzenmann@feddit.org
          link
          fedilink
          English
          arrow-up
          2
          ·
          1 day ago

          I actually did this. It did not end up being any faster than the brute-force solution since it seems to only catch the easy cases

          • lwhjp@lemmy.sdf.org
            link
            fedilink
            arrow-up
            1
            ·
            edit-2
            19 hours ago

            Perhaps your implementation continues the search longer than necessary? I got curious and tried it myself. Runtime went from 0.599s (brute force) to 0.017s.