[SPOILER] Optimized slow solution
James Mastros <[email protected]>
| Newsgroups | gmane.comp.lang.perl.qotw.discuss |
|---|---|
| Message-ID | <[email protected]> |
The below solution is pretty much the "obvious" recursive solution with
some optimizations -- the removal of extra scopes by using
statement-modifier ifs and the removal of argument shuffling, mostly.
It could be optimized a bit further by removal of the gotone coderef,
and hardcoding two different versions, one of which prints out the
answer, and the other of which does nothing (and thereby avoids the
call), but that would have impacted maintainability. (The program is
warnings and strict compliant, I believe, but does not use them because
they can have a (slight) performance loss.)
The only algorithmic optimization is that it will generate all needed
closing parens if there is no more room for open parens.
I'll probably write my own faster way, after glancing at the other
spoiler posts people have written. Somewhat oddly, I tried using the
goto &sub and the goto bareword forms for the ')' call to inner, and
found that it was actually a pessimization.
my $gotone;
# The program should print all the properly-balanced strings of
# parentheses of length 2n.
sub outer {
$gotone=sub {print "Answer: ", @_, "\n"};
inner('', (shift)*2, 0);
}
my ($calls, $deadends)=0;
use constant SOFAR=>0;
use constant SIZELEFT=>1;
use constant NOWOPEN=>2;
use constant GOTONE=>3;
sub inner {
# $calls++;
# print join(', ', @_);
$gotone->($_[SOFAR] . ')' x $_[SIZELEFT]), return
if ($_[NOWOPEN] == $_[SIZELEFT]);
# print "<" if ($_[SIZELEFT]>$_[NOWOPEN]);
# print ">" if ($_[NOWOPEN]);
# print "\n";
inner($_[SOFAR].'(', $_[SIZELEFT]-1, $_[NOWOPEN]+1)
if ($_[SIZELEFT]>$_[NOWOPEN]);
inner($_[SOFAR].')', $_[SIZELEFT]-1, $_[NOWOPEN]-1)
if ($_[NOWOPEN]);
}
# Comment these out for a table of n vs time.
outer shift;
exit;
foreach my $n (0..100) {
my ($startu, $starts) = times;
$calls=0;
$gotone=sub{};
inner('', $n*2, 0, sub{});
my ($endu, $ends) = times;
print join(' ', $n, ($endu+$ends)-($startu+$starts), $calls), "\n";
}