diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2023-03-13 07:46:00 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-13 07:46:00 +0000 |
| commit | 42c2d3ce36061d0b889fc60545fe6740198dd94d (patch) | |
| tree | 4b0ab0a649f2bf06511acb9ebe45e42931977cad | |
| parent | a8b1837fcd58b7589791e42b2ef4788e0e8ed7d7 (diff) | |
| parent | d6678cdb0f720fef4dfcaa6e80396a3b546b2518 (diff) | |
| download | perlweeklychallenge-club-42c2d3ce36061d0b889fc60545fe6740198dd94d.tar.gz perlweeklychallenge-club-42c2d3ce36061d0b889fc60545fe6740198dd94d.tar.bz2 perlweeklychallenge-club-42c2d3ce36061d0b889fc60545fe6740198dd94d.zip | |
Merge pull request #7712 from drbaggy/master
Finally had time to write up!
| -rw-r--r-- | challenge-207/james-smith/README.md | 110 | ||||
| -rw-r--r-- | challenge-207/james-smith/blog.txt | 1 | ||||
| -rw-r--r-- | challenge-207/james-smith/perl/ch-1.pl | 22 | ||||
| -rw-r--r-- | challenge-207/james-smith/perl/ch-2.pl | 21 |
4 files changed, 110 insertions, 44 deletions
diff --git a/challenge-207/james-smith/README.md b/challenge-207/james-smith/README.md index 4c0ad820a2..367b308981 100644 --- a/challenge-207/james-smith/README.md +++ b/challenge-207/james-smith/README.md @@ -1,7 +1,7 @@ -[< Previous 205](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-205/james-smith) | -[Next 207 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-207/james-smith) +[< Previous 206](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-206/james-smith) | +[Next 208 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-208/james-smith) -# The Weekly Challenge 206 +# The Weekly Challenge 207 You can find more information about this weeks, and previous weeks challenges at: @@ -13,69 +13,91 @@ 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-2065/james-smith +https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-207/james-smith -# Task 1: Shortest Time +# Task 1: Keyboard Word -***You are given a list of time points, at least 2, in the 24-hour clock format `HH:MM`. Write a script to find out the shortest time in minutes between any two time points.*** +***You are given an array of words. Write a script to print all the words in the given array that can be types using alphabet on only one row of the keyboard. (Assuming as English this is a QWERTY keyboard)*** ## Solution -We will do a pairwise comparison of each pair. The shortest time for any pair is either going from the absolute differences in times directly - OR going through midnight. These are `abs( t1 - t2 )` or `abs( t1 + t2 - 1440 )`. The code becomes: +The obvious solution here is to use a regular expression, where each row of the keyboard is separated by a `|` to make them separate clauses. ```perl -sub shortest_time { - my $min = 1_440, @_ = map { @Q = split /:/; $Q[0]*60 + $Q[1] } @_; - while( defined (my $t = shift) ) { - abs( $t-$_ ) < $min && ( $min = abs $t-$_ ), - abs( $t+$_-1_440 ) < $min && ( $min = abs $t+$_-1_440 ) for @_; - } - $min -} +sub keyboard_words { grep { m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i } @_ } ``` -Now how efficient is this - though - is there a better way to use built-in perk functions? - -If we sort the times in order, we only have to compare the `n` gaps, from the last to the first through midnight and each of the subsequent neighbours. - -This gives us two alternative code blocks: +We can loop through a file with the following code to find the longest keyboard words in the dictionary ```perl -sub shortest_time { - @_ = map { my @Q = split /:/; $Q[0]*60 + $Q[1] } sort @_; - my $min = 1440 + (my $t = shift) - $_[-1]; - ($_-$t<$min) && ($min=$_-$t), $t=$_ for @_; - $min -} +m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i && print while <> ``` -or: +**or** as a bash one-liner: -```perl -sub shortest_time { - @_ = sort { $a<=>$b } map { my @Q = split /:/; $Q[0]*60 + $Q[1] } @_; - my $min = 1440 + (my $t = shift) - $_[-1]; - ($_-$t<$min) && ($min=$_-$t), $t=$_ for @_; - $min -} +```bash +perl -ne 'm{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i&&print' /usr/share/dict/british-english-huge ``` -Which of these is fastest? The `sort` method is much more efficient than the pairwise approach (It's `O(n.log n)` where the pairwise solution is `O(n^2)`. Of the two the second numeric `sort` after the `map` if slightly faster than the `map` after the string `sort`. +This gives us the following for longest words: + +Length 11: + + * rupturewort + +Length 10: + * peppertree + * pepperwort + * perpetuity + * perruquier + * pirouetter + * prerequire + * proprietor + * repertoire + * typewriter + +Note these are all on the top row of the keyboard - So no **typewriter** isn't the longest word in the English language you can make from the top row of the keyboard. + +Using this extreme dictionary - we have: -# Task 2: Array Pairings +| Length | Count | ++--------+-------+ +| 11 | 1 | +| 10 | 9 | +| 9 | 27 | +| 8 | 70 | +| 7 | 128 | +| 6 | 224 | +| 5 | 278 | +| 4 | 322 | +| 3 | 285 | +| 2 | 218 | +| 1 | 52 | -***You are given an array of integers having even number of elements. Write a script to find the maximum sum of the minimum of each pairs.*** +Note: the definition of a word is a bit vague at times.... + +Note: there are 5 9-letter words which are not from the top row - these are all of Jewish origin. + +# Task 2: H-index + +***You are given an array of integers containing citations a researcher has received for each paper. Write a script to compute the researcher’s H-Index. For more information please checkout the wikipedia page.*** + +***The H-Index is the largest number h such that h articles have at least h citations each. For example, if an author has five publications, with 9, 7, 6, 2, and 1 citations (ordered from greatest to least), then the author’s h-index is 3, because the author has three publications with 3 or more citations. However, the author does not have four publications with 4 or more citations.*** ## Solution -There is a trick here - the optimal solution is achieved by sorting the array into order and then chunking into to pairs... Then take the minimum of each... +This is actually relatively straight forward (we will assume that the reference counts are in order). ```perl -sub max_sum_pair_min { - my $t = 0, @_ = sort {$a<=>$b} @_; - $t += shift, shift while @_; - $t -} +sub h_index { ( $_[$_]>$_) && return $_+1 for reverse 0..$#_ } +sub h_index_2 { pop @_ while $_[-1] < @_; 0 + @_ } +sub h_index_3 { ( $_[$_]>$_) || return $_ for 0..$#_; 0+@_ } ``` -When we `shift`, `shift` the first value is added to the total, the second value is discarded. +We can either start at the beginning of the list and count backwards *OR* from the start. + +`h_index_3` starts from the beginning of the list. We assume if we are not past the threshold then the `h-index` is the previous index - as in the real world our list is 1-based and in the perl world 0-based - then this is just `$_`. We short cut the loop and return the value. If we don't short cut the loop then the index must be the length of the list. + +`h_index` is slightly longer! But we start from the end of the list (we `reverse` the indicies). Again we use the same criteria but switch the *logic* to `&&` which is the equivalent of `if`. And loop until we match the criteria. In this case we return `$_+1` as it is the current one we are interested in. **Note** in this case we will always short cut the loop so need no additional `return` state - definitely a one-liner! + +`h_index_2` is effectively the same as 1, but removes the nasty use of `&&`/`||` to replace and `if`/`unless` - by putting the logic in the `while` statement and `pop`ping off values.. diff --git a/challenge-207/james-smith/blog.txt b/challenge-207/james-smith/blog.txt new file mode 100644 index 0000000000..e6225e3f9b --- /dev/null +++ b/challenge-207/james-smith/blog.txt @@ -0,0 +1 @@ +https://github.com/manwar/perlweeklychallenge-club/blob/master/challenge-207/james-smith/blog.txt diff --git a/challenge-207/james-smith/perl/ch-1.pl b/challenge-207/james-smith/perl/ch-1.pl new file mode 100644 index 0000000000..cc900a7700 --- /dev/null +++ b/challenge-207/james-smith/perl/ch-1.pl @@ -0,0 +1,22 @@ +#!/usr/local/bin/perl + +use strict; +use warnings; +use feature qw(say); +use Test::More; + +my @TESTS = ( + [ [qw(Hello Alaska Dad Peace)], 'Alaska Dad' ], + [ [qw(OMG Bye) ], '' ], +); + +is( "@{[ keyboard_words( @{$_->[0]} ) ]}", $_->[1] ) for @TESTS; + +done_testing(); + +sub keyboard_words { grep { m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i } @_ } +sub keyboard_word { $_[0] =~ m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i } + +## This one looks for all keyboard words in a file... +keyboard_word($_)&&print while<>; +m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i && print while <>; diff --git a/challenge-207/james-smith/perl/ch-2.pl b/challenge-207/james-smith/perl/ch-2.pl new file mode 100644 index 0000000000..bc06c9c57d --- /dev/null +++ b/challenge-207/james-smith/perl/ch-2.pl @@ -0,0 +1,21 @@ +#!/usr/local/bin/perl + +use strict; +use warnings; +use feature qw(say); +use Test::More; + +my @TESTS = ( + [ [10,8,5,4,3], 4 ], + [ [25,8,5,3,3], 3 ], +); + +is( h_index( @{$_->[0]} ), $_->[1] ) for @TESTS; +is( h_index_2( @{$_->[0]} ), $_->[1] ) for @TESTS; +is( h_index_3( @{$_->[0]} ), $_->[1] ) for @TESTS; + +done_testing(); + +sub h_index { ( $_[$_]>$_) && return $_+1 for reverse 0..$#_ } +sub h_index_2 { pop @_ while $_[-1] < @_; 0 + @_ } +sub h_index_3 { ( $_[$_]>$_) || return $_ for 0..$#_; 0+@_ } |
