diff options
| author | Mark <53903062+andemark@users.noreply.github.com> | 2024-03-16 11:56:29 +0000 |
|---|---|---|
| committer | Mark <53903062+andemark@users.noreply.github.com> | 2024-03-16 11:56:29 +0000 |
| commit | 473c714ee1f14bc4abbfd35b284392a567e36c02 (patch) | |
| tree | d636048008a3b73f0d8f36e2f051f75f797cfa12 | |
| parent | 2bedb7bfa99f81df85ed29b48a10bfd9e10a9c5e (diff) | |
| download | perlweeklychallenge-club-473c714ee1f14bc4abbfd35b284392a567e36c02.tar.gz perlweeklychallenge-club-473c714ee1f14bc4abbfd35b284392a567e36c02.tar.bz2 perlweeklychallenge-club-473c714ee1f14bc4abbfd35b284392a567e36c02.zip | |
blog for ch-2
| -rw-r--r-- | challenge-260/mark-anderson/raku/blog-2.md | 143 | ||||
| -rw-r--r-- | challenge-260/mark-anderson/raku/ch-2.raku | 6 |
2 files changed, 146 insertions, 3 deletions
diff --git a/challenge-260/mark-anderson/raku/blog-2.md b/challenge-260/mark-anderson/raku/blog-2.md new file mode 100644 index 0000000000..3ed5fccd92 --- /dev/null +++ b/challenge-260/mark-anderson/raku/blog-2.md @@ -0,0 +1,143 @@ +# Weekly Challenge #260 + +### Task 2: Dictionary Rank +**Submitted by: Mark Anderson** + +You are given a word, ```$word```. + +Write a script to compute the dictionary rank of the given word. + +#### Example 1 +``` +Input: $word = 'CAT' +Output: 3 + +All possible combinations of the letters: +CAT, CTA, ATC, TCA, ACT, TAC + +Arrange them in alphabetical order: +ACT, ATC, CAT, CTA, TAC, TCA + +CAT is the 3rd in the list. +Therefore the dictionary rank of CAT is 3. +``` + +#### Example 2 +``` +Input: $word = 'GOOGLE' +Output: 88 +``` + +#### Example 3 +``` +Input: $word = 'SECRET' +Output: 255 +``` + +--- + +### Solution + +One approach is to create all permutations, sort them, and find the index of ```$word```. + +This is fine for short words but there's a better solution for long words. + +There are numerous videos on youtube explaining the algorithm - I think this a good one [https://www.youtube.com/watch?v=-MpL0X3AHAs](https://www.youtube.com/watch?v=-MpL0X3AHAs) + +Here's the gist of the algorithm: + +1. Find the rank of each letter. + + ``` + G O O G L E + 1 3 3 1 2 0 + ``` + +2. For each letter, find the number of letters to its right that have a lower rank. + + ``` + G O O G L E + 1 3 3 1 1 0 + ``` + +3. For each letter, take the number of repeating letters from that letter to the end of the string. + Take the factorial of each result and multiply them together. + + ``` + G O O G L E + 2!*2! 2! 1! 1! 1! 1! + ``` + + Starting with the first letter, there are 2 Gs and 2 Os so we end up with 2!*2!. + The next letter is O. From that letter to the end of the string there is just the repeating O so we end up with 2! + and so on. + +4. Take the terms from step 2 and divide them by the terms from step 3. + + ``` + G O O G L E + 1/4 3/2 3/1 1/1 1/1 0/1 + ``` + +5. Create the sequence ```$word```.end...0 and take the factorial of each term. + + ``` + G O O G L E + 5! 4! 3! 2! 1! 0! + ``` + +6. Multipy the terms from step 4 with the terms from step 5. + + ``` + G O O G L E + 120/4 (3*24)/2 3*6 1*2 1*1 0*1 + ``` + +7. Sum the terms from step 6 and add 1 for a result of 88. + ``` + G O O G L E + 30 + 36 + 18 + 2 + 1 + 0 + 1 = 88 + ``` +### My translation to Raku: + +``` +#!/usr/bin/env raku +use experimental :cached; + +say rank('google'); + +sub postfix:<!>($n) is cached { [*] 1..$n } + +sub rank($word) +{ + my @w = $word.comb; + my @ranks = @w.sort.squish.antipairs.Map{@w}; + my $bag = @ranks.BagHash; + + my @n = gather for @ranks -> $r + { + my @less-than = $bag.keys.grep(* < $r); + take ([+] $bag{@less-than}) / ([*] $bag.values>>!); + $bag{$r}-- + } + + 1 + [+] @n Z* (@ranks.end...0)>>! +} +``` + + +For step 3 I originally had this in the for loop: + +``` +my @repeated = $bag.values.grep(* > 1); +take ([+] $bag{@less-than}) / ([*] @repeated>>!); +``` + +but grepping for values > 1 isn't necessary since 1! == 1 and then multiplying by that 1 +doesn't change anything. + +[The full program.](https://github.com/manwar/perlweeklychallenge-club/blob/master/challenge-260/mark-anderson/raku/ch-2.raku) + +Thank you for reading my solution to the [Weekly Challenge #260 Task #2.](https://theweeklychallenge.org/blog/perl-weekly-challenge-260/) + +*-Mark Anderson* diff --git a/challenge-260/mark-anderson/raku/ch-2.raku b/challenge-260/mark-anderson/raku/ch-2.raku index 5ce6cbbee5..f9bfe1af2b 100644 --- a/challenge-260/mark-anderson/raku/ch-2.raku +++ b/challenge-260/mark-anderson/raku/ch-2.raku @@ -14,10 +14,10 @@ is rank('1100010001100001111100000010101010001101111111111100101011100001').Int, sub postfix:<!>($n) is cached { [*] 1..$n } -sub rank($s) +sub rank($word) { - my @a = $s.comb; - my @ranks = @a.sort.squish.antipairs.Map{@a}; + my @w = $word.comb; + my @ranks = @w.sort.squish.antipairs.Map{@w}; my $bag = @ranks.BagHash; my @n = gather for @ranks -> $r |
