Approach 1 has the potential much faster and uses less space.
Especially for the byte code toolkit, I would first apply approach 1.
And then, when that works, replace both lists with non-shared lists that use primitive types instead of Integer and Double objects.
Please note that int requires 4 bytes, and Integer (Object) - 16-20 bytes, depending on the machine (16 on PC, 20 on android).
The list can be replaced with GrowingIntArray (I found that in the Apache statistical package, if I remember correctly), which uses primitive ints. (Or maybe just replaced int [] when you know the content can no longer change) Then you just write your own GrowingDoubleArray (or use double [])
Remember that collections are convenient, but slower.
Objects use 4 times more space than primitives.
Byte code tools require performance; it is not software that runs once a week.
Finally, I would not replace non-universal Maps, which seems to me a lot of work. But you can try this as a last step.
As a final optimization step: see how many items are in your lists or maps. If it's usually less than 16 (you should try this), you can switch to a linear search, which is the fastest, for a very small number of items. You can even make your code smart for switching search algorithms as soon as the number of elements exceeds a certain number. (Sun / Oracle java does this, and Apple / ios, to) in some of its Collections. However, this last step will make the code much more complicated.
Space as an example:
DecisionNode: 16 for class + 4 (id) + 20 (Double) +4 (boolean) = 44 + 4 padding until the next multiple of 8 = 48 bytes.