diff options
| author | drbaggy <js5@sanger.ac.uk> | 2022-03-07 21:36:16 +0000 |
|---|---|---|
| committer | drbaggy <js5@sanger.ac.uk> | 2022-03-07 21:36:16 +0000 |
| commit | 460e5dcfaaa40abab1aaa322a2d9fbe28091ceae (patch) | |
| tree | ba40a6935ecf5a6e3773544ea4c4eda852f7a086 /challenge-155 | |
| parent | 6345ed685fc976500248cac5a0485f4c94d15e2b (diff) | |
| download | perlweeklychallenge-club-460e5dcfaaa40abab1aaa322a2d9fbe28091ceae.tar.gz perlweeklychallenge-club-460e5dcfaaa40abab1aaa322a2d9fbe28091ceae.tar.bz2 perlweeklychallenge-club-460e5dcfaaa40abab1aaa322a2d9fbe28091ceae.zip | |
first pass
Diffstat (limited to 'challenge-155')
| -rw-r--r-- | challenge-155/james-smith/README.md | 99 | ||||
| -rw-r--r-- | challenge-155/james-smith/blog.txt | 1 | ||||
| -rw-r--r-- | challenge-155/james-smith/perl/ch-1.pl | 18 | ||||
| -rw-r--r-- | challenge-155/james-smith/perl/ch-2.pl | 19 |
4 files changed, 72 insertions, 65 deletions
diff --git a/challenge-155/james-smith/README.md b/challenge-155/james-smith/README.md index b3bf5a6fb5..2f4f424197 100644 --- a/challenge-155/james-smith/README.md +++ b/challenge-155/james-smith/README.md @@ -1,6 +1,6 @@ -[< Previous 153](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-153/james-smith) | -[Next 155 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-155/james-smith) -# The Weekly Challenge #154 - `do` and `redo` there is no `try`! +[< Previous 154](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-154/james-smith) | +[Next 156 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-156/james-smith) +# The Weekly Challenge #155 You can find more information about this weeks, and previous weeks challenges at: @@ -12,90 +12,59 @@ submit solutions in whichever language you feel comfortable with. You can find the solutions here on github at: -https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-154/james-smith +https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-155/james-smith -# Challenge 1 - Missing Permutation +# Challenge 1 - Fortunate Numbers -***You are given possible permutations of the string 'PERL'. Find any missing ones*** +***Write a script to produce first 8 Fortunate Numbers (unique and sorted) - A Fortunate number, named after Reo Fortune, is the smallest integer `m > 1` such that, for a given positive integer `n`, `pn# + m` is a prime number, where the primorial `pn#` is the product of the first `n` prime numbers.*** -## Solution 1 - answering the question - not the input data! +## The solution -The input is a special case of the data where there is only one missing solution. We will show -in solution 2 how this can be "solved" with much smaller code! +To make this easier we use the useful function `next_prime` from Math::Prime::Util. This finds the first prime greater than the parameter past. -For solving for the general case we need to work through all the permutations and see if they -are not present in our list. To do the check we start by using the classic Perl solution of making -the words the keys of a hash! +We use it two ways: -For the permutations, we create an array of the letters in the words in alphabetic order in this -case `('E','L','P','R')`, and each stage we rearrange the letters so they are next in alphabetic -order `('E','L','P','R')` to `('E','L','R','P')` to `('E','P','L','R')` ... `('R','P','L','E')` + * To get the next prime in the list; + * To find `m` by computing the next prime after the current prime product (we have to add 2 so that we avoid the one that is 1 higher than the product) -The code to do this is. -```perl -sub next_perm { - my( $i, $j ); - ( $s[$_] lt $s[$_+1] ) && ( $i = $_ ) for 0 .. @s-2; - return unless defined $i; - ( $s[$i] lt $s[$_ ] ) && ( $j = $_ ) for $i+1 .. @s-1; - @s[ $i, $j ] = @s[ $j, $i ]; - @s[ $i+1 .. @s-1 ] = @s[ reverse $i+1 .. @s-1 ]; - return join '',@s; -} -``` +Doing this gives a list of unique fortunate numbers, which we then sort to display them -This was written up for a previous challenge. It avoids having to use a recursive call. Due to -the way the code is written it automatically removes duplicates. - -The overall code then reduces to: +Note without doing an exhaustive search there may be a prime product for which `m` is 11 (for instance) ```perl -my $w = join '', @s = sort split //, 'PERL'; ## set up initial word -my %check = map { $_=>1 } @words; ## create look up -do { exists $check{$w} || say " * $w" } while $w = next_perm; ## loop until complete -``` +use Math::Prime::Util qw(next_prime); -We have to use `do { } while` rather than `while() { }` so that -we execute the functions in the loop BEFORE the check, otherwise -we miss the first order "`ELPR`". +my %res; -## Solution 2 - if we know there is only 1 missing permutation and all words in the list are unique!! +for( my $p = my $pp = 2; + $pp < 1<<63; + $pp *= $p = next_prime($p) +) { + $res{ next_prime($pp+2) - $pp } = 1; +} -```perl -my $r =''; -$r^=$_ for @words; -say $r; +say for sort { $a <=> $b } keys %res; ``` -This works by bit flipping each of the words in the list of permutations. For each letter - if flipped -twice it returns to the null `\0` character - so if flipped an odd number of times is the letter itself. -We note that in the permutation list - for the 23 combinations, each character is flipped 6 times in -each location EXCEPT for the characters of the missing word (where it will be 5)...! - -# Challange 2 - Padovan Prime +# Challange 2 - Pisano Period -***A Padovan Prime is a Padovan Number that’s also prime. The Padovan sequence is the sequence of integers P(n) defined by the initial values: P(0) = P(1) = P(2) = 1 and then the relationship P(n) = P(n-2) + P(n-3). Find the first 10 distinct solutions.*** +***Write a script to find the period of the 3rd Pisano Period. - In number theory, the nth Pisano period, written as π(n), is the period with which the sequence of Fibonacci numbers taken modulo n repeats.*** ## The solution -By using `is_prime` from the `Math::Prime::Util` we can quickly check to see if a number is prime. We then have to generate the Padovan sequence. We can generate the whole sequence - but that isn't needed for this problem we only need the values to create the next number, if we define these as `p, q, r` we note that to get the next one in the sequence we can define `(p',q',r') = (q,r,p+q);` +For `n>1` we note that the repeated sequence must start with `1, 1` (and if it is `1, 1` the sequence will be repeated). We also realise we can avoid 2 loops in that the end of the sequence must be `1, 0`. Again we don't need to keep the whole finonacci sequence just the last two values. ```perl -my$p=my$q=my$r=1; -($p,$q,$r)=($q,$r,$p+$q),$r!=$q&&is_prime($r)?say$r:redo for 1..10; +sub pisano_period { + return 1 if $_[0]==1; + my ($n,$c,$p,$q) = (shift,2,1,1); + $c++,($p,$q)=($q,($p+$q)%$n) while $q || $p!=1; + return $c; +} ``` -Expanding this out gives.. +Notes: + * The first line checks for the special case when `n=1` in which all values in the sequence are `0` so repeat has length 1. + * `$c` is initialized as `2` as we are checking for the end of the loop not the beginning of the next... {so need to add the two initial values (1,1)} -```perl -$p=$q=$r=1; - -for (1..10) { - ( $p, $q, $r ) = ( $q, $r, $p+$q ); - redo if $r == $q; ## skip (redo loop) if same as previous value - redo unless is_prime($r); ## skip (redo loop) if not prime - say $r; ## output if we get here! -} -``` -Note we use a *little used* perl construct - `redo` which restarts the loop without incrementing the counter. So in this case finds the next padovan number without incrementing the counter in the outside loop. So to find 10 answers, we just loop from 1 to 10. diff --git a/challenge-155/james-smith/blog.txt b/challenge-155/james-smith/blog.txt new file mode 100644 index 0000000000..a67bedeb57 --- /dev/null +++ b/challenge-155/james-smith/blog.txt @@ -0,0 +1 @@ +https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-155/james-smith diff --git a/challenge-155/james-smith/perl/ch-1.pl b/challenge-155/james-smith/perl/ch-1.pl new file mode 100644 index 0000000000..8b00b52d59 --- /dev/null +++ b/challenge-155/james-smith/perl/ch-1.pl @@ -0,0 +1,18 @@ +#!/usr/local/bin/perl + +use strict; + +use warnings; +use feature qw(say); +use Math::Prime::Util qw(next_prime); + +my %res; + +for( my $p = my $pp = 2; + $pp < 1<<63; + $pp *= $p = next_prime($p) +) { + $res{ next_prime($pp+2) - $pp } = 1; +} + +say for sort { $a <=> $b } keys %res; diff --git a/challenge-155/james-smith/perl/ch-2.pl b/challenge-155/james-smith/perl/ch-2.pl new file mode 100644 index 0000000000..59160e1ff1 --- /dev/null +++ b/challenge-155/james-smith/perl/ch-2.pl @@ -0,0 +1,19 @@ +#!/usr/local/bin/perl + +use strict; + +use warnings; +use feature qw(say); +use Test::More; +use Benchmark qw(cmpthese timethis); +use Data::Dumper qw(Dumper); + +printf "%4d %8d\n", $_,pisano_period( $_ ) for 1..(@ARGV?$ARGV[0]:144); + +sub pisano_period { + return 1 if $_[0]==1; ## Special case $n==1 sequence is just "0" + my ($n,$c,$p,$q) = (shift,2,1,1); + $c++,($p,$q)=($q,($p+$q)%$n) while $q || $p!=1; ## End of sequence ($p,$q)=(1,0) + return $c; +} + |
