I'm having a problem with a task similar to this one: click (translated) (the one I was assigned with has way bigger tests and a lower time limit). A quick translation of the task:
Write a program that checks how many times the given number occurred in a given sequence.
Input: Given number, how many numbers are in the sequence, the sequence of numbers
Output: The number of occurrences
My solutions so far:
1:
#!/usr/bin/env perl
while (<>) {
$in = $_;
@nums = split / /, $in, 3;
$what = shift @nums;
shift @nums;
$rest = shift @nums;
$rest = " ".$rest." ";
$sum = () = $rest =~ /(?<=\s)$what(?=\s)/g;
print $sum;
print "\n";
}
2:
#!/usr/bin/env perl
while (<>) {
$in = $_;
@nums = split / /, $in, 3;
$what = shift @nums;
shift @nums;
$rest = shift @nums;
$rest = " ".$rest." ";开发者_运维百科
if(!$reg{$what}){
$reg{$what} = qr/(?<=\s)$what(?=\s)/;
}
$sum = () = $rest =~ /$reg{$what}/g;
print $sum;
print "\n";
}
I also tried the brute force approach, hash tables, grep... All exceed the given time limit, and I've got no idea how to write anything that will work faster than the above two. Any ideas?
edit: After getting rid of copying lists (turns out the numbers can also be negative):
#!/usr/bin/env perl
while ($line = <>) {
$line =~ s/^(-?\d+) \d+//;
$what = $1;
$sum = () = $line =~ / $what\b/g;
print $sum;
print "\n";
}
edit2: via http://www.chengfu.net/2005/10/count-occurrences-perl/:
print $sum = (($line =~ s/ $1\b//g)+0);
resulted in 2x faster code than:
print $sum = () = $line =~ / $1\b/g;
Works now, thanks :)
For one thing, you're doing an awful lot of copying. I've marked each time you copy a large string in your first example:
while (<>) {
$in = $_; # COPY
@nums = split / /, $in, 3; # COPY
$what = shift @nums;
shift @nums;
$rest = shift @nums; # COPY
$rest = " ".$rest." "; # COPY
$sum = () = $rest =~ /(?<=\s)$what(?=\s)/g;
print $sum;
print "\n";
}
To speed things up, avoid the copies. For example, use while ($in = <>)
(or just skip $in
and use $_
).
For extracting $what
and the count, I think I'd try this instead of split
:
$in =~ s/^(\d+) \d+//;
$what = $1;
Instead of adding a space fore and aft, just use \b
instead of lookarounds with \s
.
$sum = () = $in =~ /\b$what\b/g;
精彩评论