From 52ff46a5a77556c683268b6ad06d1ef716312480 Mon Sep 17 00:00:00 2001 From: dcw Date: Sun, 11 Aug 2019 17:45:33 +0100 Subject: Checked in my (dcw)'s solutions for this week --- challenge-020/duncan-c-white/README | 29 +++++++++----- challenge-020/duncan-c-white/perl5/ch-1.pl | 25 ++++++++++++ challenge-020/duncan-c-white/perl5/ch-2.pl | 61 ++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 9 deletions(-) create mode 100755 challenge-020/duncan-c-white/perl5/ch-1.pl create mode 100755 challenge-020/duncan-c-white/perl5/ch-2.pl 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"; +} -- cgit