aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-216/james-smith/README.md125
1 files changed, 63 insertions, 62 deletions
diff --git a/challenge-216/james-smith/README.md b/challenge-216/james-smith/README.md
index 12dc6c8035..1518a7f6e6 100644
--- a/challenge-216/james-smith/README.md
+++ b/challenge-216/james-smith/README.md
@@ -1,7 +1,7 @@
-[< Previous 214](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-214/james-smith) |
-[Next 216 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-216/james-smith)
+[< Previous 215](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-215/james-smith) |
+[Next 217 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-217/james-smith)
-# The Weekly Challenge 215
+# The Weekly Challenge 216
You can find more information about this weeks, and previous weeks challenges at:
@@ -13,84 +13,85 @@ 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-215/james-smith
+https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-216/james-smith
-# TASK #1: Odd one Out
+# TASK #1: Registration Number
-***You are given a list of words (alphabetic characters only) of same size. Write a script to remove all words not sorted alphabetically and print the number of words in the list that are not alphabetically sorted.***
+***You are given a list of words and a random registration number. Write a script to find all the words in the given list that has every letter in the given registration number.***
## Solution
-To solve this problem we loop though each string to make sure the letters in alphabetical order.
-
-We note that if the words are 1 character long then they will be default in alphabetical order so we return 0.
-
-Looping through the letters - we just see if one is greater than or equal to the previous one - if it isn't we update the counter and move on to the next word.
-
-Note we use a ternary to replace this `if`/`else` for compactness.
-
-```perl
-sub non_alpha {
- return 0 if length $_[0] <2;
- my($c,$f)=0;
- for(@_) {
- $f='';
- $f gt $_ ? ($c++,last) : ($f=$_) for split //;
- }
- $c
-}
-```
-
-We can compact this by converting the inner `for` into a `map` - note the `last` was on the inner loop - and is the same as a `next` on the outer loop... So here we have to now use `next` not `laat`
-
```perl
-sub non_alpha_compact {
- return 0 if length $_[0] <2;
- my($c,$f)=0;
- $f='', map { $f gt $_ ? ($c++,next) : ($f=$_) } split // for @_;
- $c
+sub reg_number {
+ my (%l,%x) = map { /[a-z]/ ? ($_=>1) : () }
+ split //,
+ lc
+ shift;
+ grep {
+ %x=%l;
+ delete $x{$_} for split//;
+ !%x
+ } @_
}
```
-# TASK #2: Number Placement
+Firstly we get a list of the lower-cased letters in the number plate. Then for each word in turn we:
+ * copy this hash into a temporary hash;
+ * remove any letters from hash which rea in the word;
+ * Check to see if the hash is now empty - if it is we include the word.
-***You are given a list of numbers having just 0 and 1. You are also given placement count (>=1). Write a script to find out if it is possible to replace 0 with 1 in the given list. The only condition is that you can only replace when there is no 1 on either side. Print 1 if it is possible otherwise 0.***
+# TASK #2: Word Stickers
-*Question - there are two intepretations o the question - whether the placements are done simultaneously or one after the other*
-
-*In the former case any run of 3+ zeros can have `n-2` updates, but if it is the former it `(n-1)/2`
+***You are given a list of word stickers and a target word. Write a script to find out how many word stickers is needed to make up the given target word.***
## Solution
-Both solutions are the same except for the calculation at the heart to compute the count.
+Interestingly this task uses the trick - copy hash and delete elements - within it's core.
-We loop through the numbers if we see a 1 we check to see how many previous 0's we've had and compute the number of insertions. If it is 0 we increment the count of 0's in a row. Note to make sure we include any last sequence of 0's we add a 1 on to the end of the list we are search.
+We note:
+ * We are looking for fewest stickers - well this suggests a solution based on a queue as we want to do a depth based search.
```perl
-sub insert_zero {
- my($s,$c) = (0,shift);
- $_ ? ( $c-= $s>2 && int(($s-1)/2), $s=0 ) : $s++ for @_,1;
- $c>0?0:1;
-}
-
-sub insert_zero_simultaneous {
- my($s,$c) = (0,shift);
- $_ ? ( $c-= $s>2 && $s-2, $s=0 ) : $s++ for @_,1;
- $c>0?0:1
+sub word_stickers {
+ my( %f, %s, $n, $l, $x );
+ $f{$_}++ for split //, shift;
+ my @q = [ 1, 0, my %t = %f ];
+ map { delete $t{$_} } split // for @_;
+ return 0 if keys %t;
+ while( ( $n, $l, %f ) = @{ shift @q } ) {
+ push @q, map {
+ $x = 0, %t = %f;
+ exists $t{$_} && ( $x=1, --$t{$_} || delete $t{$_} )
+ for split//, $_[$_];
+ !%t ? return $n : $x ? [ $n+1, $_, %t ] : ()
+ } $l..$#_;
+ }
}
```
-We can get some performance improvements by short cutting the loop, by checking the value of $c at each stage rather than just at the end. This is most important if the number of inserts is relatively low in comparison to the size of the list.
-
```perl
-sub insert_zero_shortcut {
- my($s,$c) = (0,shift);
- $_ ? ( $c-= $s>2 && int(($s-1)/2), $s=0, $c>0 || return 1 ) : $s++ for @_,1;
- 0;
-}
-
-sub insert_zero_simultaneous_shortcut {
- my($s,$c) = (0,shift);
- $_ ? ( $c-= $s>2 && $s-2, $s=0, $c>0 || return 1 ) : $s++ for @_,1;
- 0;
+sub word_stickers {
+ my( %f, %s, $n, $l, $x );
+ $f{$_}++ for split //, shift; # count for letters
+ my %t = %f; # Check all letters on stickers
+ # Initialise queue - no stickers, initial freq.
+ my @q = [ 1, 0, my %t = %f ]; # Check can solve?
+ map { delete $t{$_} } split // for @_;
+ return 0 if keys %t; # if not return 0
+ my @q = [ 1, 0, %f ]; # [ $no+1, $last, %freqs ]
+ while( ($n,$l,%f) = @{ shift @q } ) {
+ push @q, map {
+ # Make copy of frequencies, set flag ($x)
+ # true once we use a letter on sticker,
+ # remove letters we have used up
+ $x = 0, %t = %f;
+ exists $t{$_} && ( $x=1, --$t{$_} || delete $t{$_} )
+ for split//, $_[$_];
+ # If none left return $n OR push entry onto
+ # queue, increasing count and setting new last
+ !%t ? return $n : $x ? [ $n+1, $_, %t ] : ()
+ # Loop from last used to remove duplicates
+ } $l..$#_;
+ }
}
+```