11package aminetti .adventofcode2024 .day07 ;
22
3- import com .google .common .collect .Iterables ;
43import org .apache .commons .lang3 .StringUtils ;
54import org .slf4j .Logger ;
65import org .slf4j .LoggerFactory ;
76
87import java .util .ArrayList ;
98import java .util .Arrays ;
9+ import java .util .EnumSet ;
1010import java .util .List ;
1111
12- import static aminetti .adventofcode2024 .day07 .Day07 .Op .MULT ;
12+ import static aminetti .adventofcode2024 .day07 .Day07 .Op .* ;
1313import static com .google .common .collect .Lists .newArrayList ;
1414
1515public class Day07 {
1616 private static final Logger LOGGER = LoggerFactory .getLogger (Day07 .class );
17- private List <String > input ;
1817 private final List <Long > results = new ArrayList <>();
1918 private final List <List <Long >> components = new ArrayList <>();
2019
2120 public Day07 () {
2221 }
2322
2423 public void parseInput (List <String > input ) {
25- this .input = input ;
26- 2724 for (String s : input ) {
2825 String [] split = s .split (":" );
2926 results .add (Long .parseLong (split [0 ]));
@@ -33,12 +30,19 @@ public void parseInput(List<String> input) {
3330 }
3431
3532 public long solvePart1 () {
33+ EnumSet <Op > allowedOps = EnumSet .of (SUM , MULT );
34+ return countValidEquations (allowedOps );
35+ }
36+ 37+ private long countValidEquations (EnumSet <Op > allowedOps ) {
3638 long sum = 0 ;
3739 for (int i = 0 ; i < results .size (); i ++) {
3840 Long result = results .get (i );
39- long count = countOfCorrectOperators (result , components .get (i ), List .of (), newArrayList ());
40- LOGGER .debug ("count for {}: {}" , result , count );
41- if (count > 0 ) {
41+ 42+ boolean valid = isValid (allowedOps , result , components .get (i ), List .of (), newArrayList ());
43+ LOGGER .debug ("Is {}: valid? {}" , result , valid );
44+ 45+ if (valid ) {
4246 sum += result ;
4347 }
4448 }
@@ -48,7 +52,7 @@ public long solvePart1() {
4852 public enum Op {
4953 SUM , MULT , CONCAT ;
5054
51- public String print () {
55+ public String toString () {
5256 return switch (this ) {
5357 case SUM -> "+" ;
5458 case MULT -> "*" ;
@@ -57,136 +61,79 @@ public String print() {
5761 }
5862 }
5963
64+ public long solvePart2 () {
65+ EnumSet <Op > allowedOps = EnumSet .allOf (Op .class );
66+ return countValidEquations (allowedOps );
67+ }
6068
61- private long countOfCorrectOperators (long result , List <Long > longs , List <Op > operators , List <Long > components ) {
62- if (longs .size () == 1 ) {
63- Long lastEl = Iterables .getOnlyElement (longs );
64- if (result == lastEl ) {
6569
66- String fullOperation = "(" .repeat (operators .size ()) + lastEl ;
70+ private boolean isValid (final EnumSet <Op > allowedOps , long result , List <Long > lefts , List <Op > operators , List <Long > rights ) {
71+ if (lefts .isEmpty ()) {
72+ return false ;
73+ }
6774
68- ArrayList <Op > mutableOps = newArrayList (operators );
69- ArrayList <Long > mutableComponents = newArrayList (components );
70- while (!mutableOps .isEmpty ()) {
71- fullOperation += mutableOps .removeLast ().print () + "" + mutableComponents .removeLast () + ")" ;
72- }
75+ ArrayList <Long > nextLeft = newArrayList (lefts );
76+ Long current = nextLeft .removeLast ();
7377
74- LOGGER .debug ("Operation: {}" , fullOperation );
75- LOGGER .info ("Found correct operators" );
76- return 1 ;
78+ if (lefts .size () == 1 ) {
79+ if (result == current ) {
80+ String fullOperation = printOperation (operators , rights , current );
81+ LOGGER .debug ("Found correct operators, operations: {}" , fullOperation );
82+ return true ;
7783 }
78- 79- return 0 ;
80- 84+ return false ;
8185 }
8286
83- if (result <= 0 || longs .isEmpty ()) {
84- return 0 ;
85- }
86- 87- 88- ArrayList <Op > opsForSum = newArrayList (operators );
89- opsForSum .add (Op .SUM );
9087
91- ArrayList <Op > opsForMult = newArrayList (operators );
92- opsForMult .add (MULT );
88+ ArrayList <Long > nextRights = newArrayList (rights );
89+ nextRights .add (current );
9390
94- ArrayList <Long > next = newArrayList (longs );
95- Long component = next .removeLast ();
96- 97- ArrayList <Long > nextComponents = newArrayList (components );
98- nextComponents .add (component );
99- 100- long sumMult = 0 ;
101- if (result % component == 0 ) {
102- sumMult += countOfCorrectOperators (result / component , next , opsForMult , nextComponents );
103- }
104- return sumMult
105- + countOfCorrectOperators (result - component , next , opsForSum , nextComponents );
106- }
107- 108- public long solvePart2 () {
109- long sum = 0 ;
110- for (int i = 0 ; i < results .size (); i ++) {
111- Long result = results .get (i );
112- 113- LOGGER .debug ("Checking {}" , result );
114- long count = countOfCorrectOperatorsWithConcat (result , components .get (i ), List .of (), newArrayList ());
115- LOGGER .debug ("count for {}: {}" , result , count );
116- if (count > 0 ) {
117- sum += result ;
91+ if (allowedOps .contains (MULT ) && result % current == 0 ) { // divisions are the fastest to decrease a value
92+ ArrayList <Op > opsForMult = newArrayList (operators );
93+ opsForMult .add (MULT );
94+ if (isValid (allowedOps , result / current , nextLeft , opsForMult , nextRights )) {
95+ return true ;
11896 }
11997 }
120- return sum ;
121- }
122- 123- 124- private long countOfCorrectOperatorsWithConcat (long result , List <Long > longs , List <Op > operators , List <Long > components ) {
125- if (longs .size () == 1 ) {
126- Long lastEl = Iterables .getOnlyElement (longs );
127- if (result == lastEl ) {
128- 129- String fullOperation = "(" .repeat (operators .size ()) + lastEl ;
13098
131- ArrayList <Op > mutableOps = newArrayList (operators );
132- ArrayList <Long > mutableComponents = newArrayList (components );
133- while (!mutableOps .isEmpty ()) {
134- fullOperation += mutableOps .removeLast ().print () + "" + mutableComponents .removeLast () + ")" ;
135- }
99+ String stringResult = "" + result ;
100+ String stringComponent = "" + current ;
101+ if (allowedOps .contains (CONCAT ) && stringResult .length () > stringComponent .length () && stringResult .endsWith (stringComponent )) {
102+ // split a number (~divide by 10^log10(current) ) could be slower than divisions but faster than subtractions to decrease a value
103+ ArrayList <Op > opsForConcat = newArrayList (operators );
104+ opsForConcat .add (CONCAT );
136105
137- LOGGER . debug ( "Operation: {}" , fullOperation );
138- LOGGER . info ( "Found correct operators" );
139- return 1 ;
106+ long expectedResult = Long . parseLong ( stringResult . substring ( 0 , stringResult . length () - stringComponent . length ()) );
107+ if ( isValid ( allowedOps , expectedResult , nextLeft , opsForConcat , nextRights )) {
108+ return true ;
140109 }
141- 142- return 0 ;
143- 144110 }
145111
146- if (result <= 0 || longs .isEmpty ()) {
147- return 0 ;
112+ if (allowedOps .contains (SUM ) && result - current > 0 ) {
113+ ArrayList <Op > opsForSum = newArrayList (operators );
114+ opsForSum .add (SUM );
115+ if (isValid (allowedOps , result - current , nextLeft , opsForSum , nextRights )) {
116+ return true ;
117+ }
148118 }
149119
150120
151- ArrayList <Op > opsForSum = newArrayList (operators );
152- opsForSum .add (Op .SUM );
153121
122+ return false ;
123+ }
154124
125+ private static String printOperation (List <Op > operators , List <Long > components , Long lastEl ) {
126+ StringBuilder fullOperation = new StringBuilder ("(" .repeat (operators .size ()) + lastEl );
155127
156- ArrayList <Long > next = newArrayList (longs );
157- Long component = next .removeLast ();
158- 159- ArrayList <Long > nextComponents = newArrayList (components );
160- nextComponents .add (component );
161- 162- long sumConcat = 0 ;
163- String stringResult = "" + result ;
164- String stringComponent = "" + component ;
165- 166- LOGGER .info ("Result: {} - longs: {}" , result , longs );
167- LOGGER .info ("Result: {} - stringComponent: {}" , stringResult , stringComponent );
168- 169- if (stringResult .length () > stringComponent .length () && stringResult .endsWith (stringComponent )) {
170- LOGGER .info ("Trailing matches: Result: {} - stringComponent: {}" , stringResult , stringComponent );
171- 172- ArrayList <Op > opsForConcat = newArrayList (operators );
173- opsForConcat .add (Op .CONCAT );
128+ ArrayList <Op > mutableOps = newArrayList (operators );
129+ ArrayList <Long > mutableComponents = newArrayList (components );
174130
175- long expectedResult = Long .parseLong (stringResult .substring (0 , stringResult .length () - stringComponent .length ()));
176- LOGGER .info ("expectedResult: {}" , expectedResult );
177- sumConcat += countOfCorrectOperatorsWithConcat (
178- expectedResult ,
179- next , opsForConcat , nextComponents );
131+ while (!mutableOps .isEmpty ()) {
132+ fullOperation .append (mutableOps .removeLast ())
133+ .append (mutableComponents .removeLast ()).append (")" );
180134 }
181135
182- long sumMult = 0 ;
183- if (result % component == 0 ) {
184- ArrayList <Op > opsForMult = newArrayList (operators );
185- opsForMult .add (MULT );
186- sumMult += countOfCorrectOperatorsWithConcat (result / component , next , opsForMult , nextComponents );
187- }
188- return sumMult + sumConcat
189- + countOfCorrectOperatorsWithConcat (result - component , next , opsForSum , nextComponents );
136+ return fullOperation .toString ();
190137 }
191138
192139}
0 commit comments