[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";
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.