diff options
| author | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2022-03-21 05:15:22 +0000 |
|---|---|---|
| committer | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2022-03-21 05:15:22 +0000 |
| commit | 62181ff9ca2372aa83e82cb24d0aaa0550d0e242 (patch) | |
| tree | 9b2b7db7eaa2363d6687c8326c19001fcbad9e4a /challenge-157/james-smith | |
| parent | 10943183774d5f491efc600a05a9fbda4e5cb8c2 (diff) | |
| download | perlweeklychallenge-club-62181ff9ca2372aa83e82cb24d0aaa0550d0e242.tar.gz perlweeklychallenge-club-62181ff9ca2372aa83e82cb24d0aaa0550d0e242.tar.bz2 perlweeklychallenge-club-62181ff9ca2372aa83e82cb24d0aaa0550d0e242.zip | |
- Added template for week 157.
Diffstat (limited to 'challenge-157/james-smith')
| -rw-r--r-- | challenge-157/james-smith/README.md | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/challenge-157/james-smith/README.md b/challenge-157/james-smith/README.md new file mode 100644 index 0000000000..319d3e9b43 --- /dev/null +++ b/challenge-157/james-smith/README.md @@ -0,0 +1,89 @@ +[< Previous 155](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-155/james-smith) | +[Next 157 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-157/james-smith) +# The Weekly Challenge #156 + +You can find more information about this weeks, and previous weeks challenges at: + + https://theweeklychallenge.org/ + +If you are not already doing the challenge - it is a good place to practise your +**perl** or **raku**. If it is not **perl** or **raku** you develop in - you can +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-156/james-smith + +# Challenge 1 - Pernicious Numbers + +***Write a script to permute first 10 Pernicious Numbers. - A pernicious number is a positive integer which has prime number of ones in its binary representation.*** + +## The solution + +First of all we note that we don't need that large a number of primes - for values up to 1,000 we only need 2, 3, 5 & 7; for values up to 1 million 2, 3, 5, 7, 11, 13, 17 & 19. So we therefore hard code our list of primes. + +Counting the number of `1`s in the binary representation of the number is as simple as `spintf` the number in binary (`%b`) and then countins the `1s` with `tr/1/1/`. + +We use the `redo` trick of last week to get the first `$N` or in this case first `10` - we restart the loop each time we fail to find a perminicious number without moving the the next entry in the array. + +```perl +my %p = map { $_ => 1 } 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37; + +my $n=0; + +$n++, exists $p{(sprintf '%b', $n)=~tr/1/1/} ? (say $n) : redo for 1..10; +``` + +Expanding out the `for` loop we have the slightly more readable code: + +```perl +my %p = map { $_ => 1 } 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37; +my $n = 0; +for (1..10) { + $n++; + redo unless exists $p{(sprintf '%b', $n)=~tr/1/1/}; + say $n; +} +``` + +# Challenge 2 - Weird numbers + +***You are given number, $n > 0. Write a script to find out if the given number is a Weird Number - a number for which the sum of the proper divisors (divisors including 1 but not itself) of the number is greater than the number, but no subset of those divisors sums to the number itself.*** + +## The solution + +Our function `is_weird` can be split into 3 parts: + + * Get the proper factors and their sum of the proper factors and check to see if the first condition is not true - return `0`. + * For every combination of factors see if their sum is `$n` - if true for any combination we return `0` as not weird. + * Return `1` as the number is weird. + +```perl +sub is_weird { + my($s,$n) = (0,shift); + + $s+=$_ for my @fact = (1,map { $n%$_ ? () : ( $_, $_*$_==$n ? () : $n/$_ ) } 2..sqrt($n)); + + return 0 if $s <= $n; + + for my $ind ( 0..(1<<@fact)-1 ) { + my $t = -$n; + $ind ? ($ind & 1 && ($t+=$fact[$_]) ) : last, $ind>>=1 for 0..$#fact; + return 0 unless $t; + } + + return 1; ## Weird +} +``` + +**Notes:** + + * If we push both `$_` and `$n/$_` if `$_` is a factor - we have to check to see that `$n/$_` is not `$_` or `$_*$_ != $n`. + * With `map` - to remove the entry the block needs to *return* an empty array rather than a `undef` value. + * In part two we use the bit shift operators twice. Once when getting the number of combinations which is `2^#factors` which can be re-written as `1<<#factors`. We also use it to division by 2 (throwing away remainder) inside the inner loop. + * Once index `$ind` is 0 we can exit the loop early to avoid unnecessary calculations - reduces the processing time by about 20%. This is achieved by the: `$ind ? ... : last` phrase + * We can use "`,`" to stitch multiple simple commands together in a postfix `for` loop. *Not always a good thing - but in tight inner code can make the "structure" of the overall code easier to read. + +***Note:*** + + * That last comment may be a bit frivolous - but sometimes if you expand out the inner of a loop too much you cannot see the whole of the code - and so you lose the "macro"-picture for the "micro"-picture. Someone who is looking at the code than has less idea of what is actually going on overall! You can for-instance take it for granted that the code copes the sum of each combination of factors - and then see what the overall code does with this information! |
