aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-020/duncan-c-white/README29
-rwxr-xr-xchallenge-020/duncan-c-white/perl5/ch-1.pl25
-rwxr-xr-xchallenge-020/duncan-c-white/perl5/ch-2.pl61
3 files changed, 106 insertions, 9 deletions
diff --git a/challenge-020/duncan-c-white/README b/challenge-020/duncan-c-white/README
index d120449c9b..bf5b030e87 100644
--- a/challenge-020/duncan-c-white/README
+++ b/challenge-020/duncan-c-white/README
@@ -1,14 +1,25 @@
-Challenge 1: "Write a script to display months from the year 1900 to 2019 where you find 5 weekends i.e. 5 Friday, 5 Saturday and 5 Sunday."
+Challenge 1: "Write a script to accept a string from command line and
+split it on change of character. For example, if the string is "ABBCDEEF",
+then it should split like 'A', 'BB', 'C', 'D', 'EE', 'F'."
-My notes:
+My notes: Clearly defined, sounds like a job for regexes.
-Clearly defined, although Friday isn't normally considered part of the weekend
-is it? Anyway, it's clear here that Friday - Sunday is the weekend for the
-purposes of this question. Date::Manip can do this easily enough.
+Challenge 2: "Write a script to print the smallest pair of Amicable Numbers."
-Challenge 2: "Write a script that can wrap the given paragraph at a specified
-column using the greedy algorithm."
+Amicable numbers are two different numbers so related that the sum of the
+proper divisors of each is equal to the other number. (A proper divisor
+of a number is a positive factor of that number other than the number
+itself. For example, the proper divisors of 6 are 1, 2, and 3.)
-My notes: Another clearly described problem. Greedy algorithm wiki page
-just neans: fit words on the line while they fit:-)
+The smallest pair of amicable numbers is (220, 284). They are amicable
+because the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44,
+55 and 110, of which the sum is 284; and the proper divisors of 284 are 1,
+2, 4, 71 and 142, of which the sum is 220.
+
+The first ten amicable pairs are: (220, 284), (1184, 1210), (2620,
+2924), (5020, 5564), (6232, 6368), (10744, 10856), (12285, 14595),
+(17296, 18416), (63020, 76084), and (66928, 66992)
+
+My notes: Another clearly described problem. Obvious method involves
+a bit of caching.
diff --git a/challenge-020/duncan-c-white/perl5/ch-1.pl b/challenge-020/duncan-c-white/perl5/ch-1.pl
new file mode 100755
index 0000000000..d8aa1a2c19
--- /dev/null
+++ b/challenge-020/duncan-c-white/perl5/ch-1.pl
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+#
+#
+# Challenge 1: "Write a script to accept a string from command line and
+# split it on change of character. For example, if the string is "ABBCDEEF",
+# then it should split like 'A', 'BB', 'C', 'D', 'EE', 'F'."
+#
+# My notes: Clearly defined, sounds like a job for regexes.
+#
+
+use strict;
+use warnings;
+use Function::Parameters;
+use Data::Dumper;
+
+die "Usage: ch-1.pl STRING\n" unless @ARGV==1;
+my $str = shift;
+
+# At first, I wrote:
+# while( $str =~ s/^(A+|B+|C+|D+|E+|F+|G+|H+|I+|J+|K+|L+|M+|N+|O+|P+|Q+|R+|S+|T+|U+|V+|W+|X+|Y+|Z+)//i )
+# but then I realised that the following much shorter regex would work:
+while( $str =~ s/^(([A-Za-z])\2*)// )
+{
+ print "split: $1\n";
+}
diff --git a/challenge-020/duncan-c-white/perl5/ch-2.pl b/challenge-020/duncan-c-white/perl5/ch-2.pl
new file mode 100755
index 0000000000..4e87946741
--- /dev/null
+++ b/challenge-020/duncan-c-white/perl5/ch-2.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+#
+# Challenge 2: "Write a script to print the smallest pair of Amicable Numbers."
+#
+# Amicable numbers are two different numbers so related that the sum of the
+# proper divisors of each is equal to the other number. (A proper divisor
+# of a number is a positive factor of that number other than the number
+# itself. For example, the proper divisors of 6 are 1, 2, and 3.)
+#
+# The smallest pair of amicable numbers is (220, 284). They are amicable
+# because the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44,
+# 55 and 110, of which the sum is 284; and the proper divisors of 284 are 1,
+# 2, 4, 71 and 142, of which the sum is 220.
+#
+# The first ten amicable pairs are: (220, 284), (1184, 1210), (2620,
+# 2924), (5020, 5564), (6232, 6368), (10744, 10856), (12285, 14595),
+# (17296, 18416), (63020, 76084), and (66928, 66992)
+#
+# My notes: Another clearly described problem. Obvious method involves
+# a bit of caching.
+#
+
+use strict;
+use warnings;
+use Function::Parameters;
+use Data::Dumper;
+
+die "Usage: ch-2.pl UPPERLIMIT\n" unless @ARGV==1;
+my $upper = shift;
+
+my @spd; # spd[i] == sum of proper divisors of i
+
+#
+# my $spd = sum_proper_divisors($n);
+# Generate and return the sum of all the proper divisors of $n,
+# the proper divisors are those integer divisors (factors) of $n
+# INCLUDING 1 and EXCLUDING $n ITSELF. eg the proper divisors of
+# $n==6 are 1,2 and 3, and their sum is 6.
+#
+fun sum_proper_divisors( $n )
+{
+ my $sum = 0;
+ for( my $f=1; $f<$n; $f++ )
+ {
+ next unless $n % $f == 0;
+ $sum += $f;
+ }
+ return $sum;
+}
+
+
+
+foreach my $p (2..$upper)
+{
+ $spd[$p] //= sum_proper_divisors($p);
+ my $q = $spd[$p];
+ next if $q <= $p;
+ $spd[$q] //= sum_proper_divisors($q);
+ next unless $spd[$q] == $p;
+ print "found amicable pair p=$p, q=$q (spd[p]=$spd[$p], spd[q]=$spd[$q])\n";
+}