RabbitFarm
2020-10-25
Perl Weekly Challenge 083
Part 1
You are given a string $S with 3 or more words. Write a script to find the length of the string except the first and last words ignoring whitespace.
Solution
use strict;
use warnings;
##
# You are given a string $S with 3 or more words.
# Write a script to find the length of the string
# except the first and last words ignoring whitespace.
##
sub count_most_words{
my ($s) = @_;
my $count = 0;
my @a = split(/\s/, $s);
map {$count += tr/a-zA-Z//d} @a[1 .. (@a - 2)];
return $count;
}
MAIN:{
my $S;
$S = "The Weekly Challenge";
print "$S --> " . count_most_words($S) . "\n";
$S = "The purpose of our lives is to be happy";
print "$S --> " . count_most_words($S) . "\n";
}
Sample Run
$ perl perl/ch-1.pl
The Weekly Challenge --> 6
The purpose of our lives is to be happy --> 23
Notes
Anytime I need to count characters I immediately think of tr. tr
will, of course, do character replacements but it’s return value is the number of characters which have been effected. Here with the d
option the matching characters are just deleted. This code would work exactly just as well with the d
but I figured it’d be actually less confusing to have it there and make it more clear what it was doing.
Part 2
You are given an array @A of positive numbers. Write a script to flip the sign of some members of the given array so that the sum of the all members is minimum non-negative.
use strict;
use warnings;
##
# You are given an array @A of positive numbers.
# Write a script to flip the sign of some members
# of the given array so that the sum of the all
# members is minimum non-negative.
##
sub try_all_flips{
my(@a) = @_;
my @minimum = (undef, undef, []);
for my $i (0 .. (2**(@a) - 1)){
my $b = sprintf("%0" . @a . "b", $i);
my @b = split(//, $b);
my $flip_count = 0;
map {$flip_count++ if $_ == 1} @b;
my @f;
for my $i (0 .. (@b - 1)){
if($b[$i] == 1){
push @f, (-1) * $a[$i];
}
else{
push @f, $a[$i];
}
}
my $sum = unpack("%32I*", pack("I*", @f));
if(!defined($minimum[0]) || ($sum <= $minimum[0] && $sum >= 0)){
if(defined($minimum[0]) && $sum == $minimum[0] && $flip_count < $minimum[1]){
$minimum[0] = $sum;
$minimum[1] = $flip_count;
$minimum[2] = \@f;
}
elsif(!defined($minimum[0])){
$minimum[0] = $sum;
$minimum[1] = $flip_count;
$minimum[2] = \@f;
}
elsif($sum < $minimum[0]){
$minimum[0] = $sum;
$minimum[1] = $flip_count;
$minimum[2] = \@f;
}
}
}
return @minimum;
}
MAIN:{
my @A;
my @minimum;
@A = (3, 10, 8);
@minimum = try_all_flips(@A);
print "[". join(", ", @A) . "] --> ";
print " [". join(", ", @{$minimum[2]}) . "] = " . $minimum[0] ."\n";
@A = (12, 2, 10);
@minimum = try_all_flips(@A);
print "[". join(", ", @A) . "] --> ";
print " [". join(", ", @{$minimum[2]}) . "] = " . $minimum[0] ."\n";
}
Sample Run
$ perl perl/ch-2.pl
[3, 10, 8] --> [3, -10, 8] = 1
[12, 2, 10] --> [-12, 2, 10] = 0
Notes
This is a brute force approach. I use the same method for generating all combinations that I used in Challenge 077 with the variation that here I use the generated combination to determine which elements of the list are to be flipped. After calculating the sum of each new list (with flipped elements) I check to see if this is a new minimum positive value and, if so, if it has been done with fewer flips.
posted at: 01:01 by: Adam Russell | path: /perl | permanent link to this entry