GAP can return all subgroups of $S_4$ pretty much instantaneously:
gap> AllSubgroups(SymmetricGroup(4));
[ Group(()), Group([ (1,2)(3,4) ]), Group([ (1,3)(2,4) ]), Group([ (1,4)(2,3) ]), Group([ (3,4) ]), Group([ (2,3) ]),
Group([ (2,4) ]), Group([ (1,2) ]), Group([ (1,3) ]), Group([ (1,4) ]), Group([ (2,4,3) ]), Group([ (1,3,2) ]),
Group([ (1,4,2) ]), Group([ (1,4,3) ]), Group([ (1,4)(2,3), (1,3)(2,4) ]), Group([ (3,4), (1,2)(3,4) ]),
Group([ (1,4), (1,4)(2,3) ]), Group([ (2,4), (1,3)(2,4) ]), Group([ (1,3,2,4), (1,2)(3,4) ]), Group([ (1,4,3,2), (1,
3)(2,4) ]), Group([ (1,2,4,3), (1,4)(2,3) ]), Group([ (3,4), (2,4,3) ]), Group([ (1,4), (1,4,3) ]),
Group([ (2,3), (1,3,2) ]), Group([ (1,2), (1,4,2) ]), Group([ (1,4)(2,3), (1,3)(2,4), (3,4) ]), Group([ (1,2)
(3,4), (1,3)(2,4), (1,4) ]), Group([ (1,2)(3,4), (1,4)(2,3), (2,4) ]), Group([ (1,4)(2,3), (1,3)(2,4), (2,4,3) ]),
Group([ (1,4)(2,3), (1,3)(2,4), (2,4,3), (3,4) ]) ]
$S_4$ has 24 elements ($4! = 24$).
A naive approach to generating all subgroups for a given group G would consider all possible subsets of G (i.e. power set of G). In this case, there are 16,777,216 possible subsets to consider ($2^{24} = 16777216$).
Of course, the order of each subgroup must evenly divide the order of G so we can narrow down the list of subsets to consider by using this fact (i.e. only consider subsets that have an order that evenly divides the order of G). For $S_4$ that narrows down the list to 3,587,174.
That's still a lot of sets to consider! I'd be surprised if GAP is computing the subgroups on the fly using this naive approach.
So I'm wondering how does GAP return the answer so quickly. Does GAP have the subgroups to $S_4$ (and other common groups) pre-computed?