aboutsummaryrefslogtreecommitdiff
path: root/challenge-149/james-smith/README.md
blob: a11172ed66e65c0ddf3baf0b56d98816ff2b4b20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
[< Previous 148](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-148/james-smith) |
[Next 150 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-150/james-smith)
# Perl Weekly Challenge #149

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-149/james-smith

# Challenge 1 - Fibonacci Digit Sum

***Given an input $N, generate the first $N numbers for which the sum of their digits is a Fibonacci number.***

## The solution

```perl
for( my($n,$ds,$i,$fa,$fb,%fib)=(@ARGV?$ARGV[0]:20,0,0,1,1,0,1,1,1);
     $n; $i++,$ds=0 ) {                                 ## 1
  $ds+=$_ foreach split //,$i;                          ## 2
  ($fib{$fa+$fb},$fa,$fb)=(1,$fb,$fa+$fb) if $ds > $fb; ## 3
  $n--,say $i if exists $fib{$ds};                      ## 4
}
```

**Notes:**

 * Line 1 - We initialise everything inside the for loop
   * `$n` is the number to print (and is based on what is passed at the command line)
   * `$ds` is the digit sum (Note we reset it everytime through the loop in the incremement part of the loop
   * `$i`  current value being considered
   * `$fa` & `$fb` - the highest two fibonacci numbers 
   * `%fib` hash whose keys are fibonacci numbers
 * Line 2 - Computes the digit sum by splitting number on `//` I split into 1 character blocks
 * Line 3 - Expand the fibonacci hash by 1 if the digit sum is greater than the highest fibonnaci number {we don't need to loop this as the digit sum of `$n+1` can only be at most 1 higher than that for `$n`. Note we just update $fb and $fa in this line
 * Line 4 - Check to see if the digit sum exists, print and decrement counter - and return to the start of the loop.

# Challenge 2 - Largest Square

***Given a number base, derive the largest perfect square with no repeated digits and return it as a string. (For base>10, use ‘A’..‘Z’.)***

## The solution

```perl
sub biggest_perfect_square {
  my $nt = my $m = (my $n = shift) -1;                       ## 1
  $m=$m*$n+$nt while $nt--;                                  ## 2
  O: for( my $t = int sqrt $m; ; $t -- ) {                   ## 3
    my ($q,%seen) = $t**2;                                   ## 4
    $seen{$q%$n}++?(next O):($q=int($q/$n)) while $q;        ## 5
    return $t;                                               ## 6
  }
}
```

**Notes:**

 * Line 1 - initialise `$n` the base we are looking at, and variables to compute the maximum possible square
 * Line 2 - Compute the maximum possible pandigital value for the given base - it is the digits in descending order *e.g.* `BA9876543210` for `$n=12`
 * Line 3 - Here we just loop from the maximum possible square (sqrt of max pandigital number rounded down). Loop will finish for all +be bases as `1` is a solution in all cases.
 * Line 4/5 - We loop through all digits to see if we have already seen the digit if so we skip to the next value of `$t` by using `next` with a label to not just out of this loop but to go to the next element of the outer loop.
 * If we get through the while loop we have a value - and it must be the highest.

## Results

The values for each value of $N are given below up to (base 15) - the largest value for which we can compute in perl's 64-bit architecture.

|  N | v         | v^2                | v^2 (base N)    | Time      | Evals    |
| -: | --------: | -----------------: | --------------: | --------: | -------: |
|  2 |         1 |                  1 |               1 |  0.000020 |        1 |
|  3 |         1 |                  1 |               1 |  0.000022 |        4 |
|  4 |        15 |                225 |            3201 |  0.000014 |        1 |
|  5 |        24 |                576 |            4301 |  0.000043 |       31 |
|  6 |       195 |              38025 |          452013 |  0.000029 |       17 |
|  7 |       867 |             751689 |         6250341 |  0.000045 |       28 |
|  8 |      3213 |           10323369 |        47302651 |  0.001050 |      841 |
|  9 |     18858 |          355624164 |       823146570 |  0.000947 |      671 |
| 10 |     99066 |         9814072356 |      9814072356 |  0.000476 |      315 |
| 11 |    528905 |       279740499025 |     A8701245369 |  0.004091 |     2564 |
| 12 |   2950717 |      8706730814089 |    B8750A649321 |  0.035980 |    22903 |
| 13 |   4809627 |     23132511879129 |    CBA504216873 | 18.936489 | 12533147 |
| 14 | 105011842 |  11027486960232964 |  DC71B30685A924 |  0.143197 |    89326 |
| 15 | 659854601 | 435408094460869201 | EDAC93B24658701 |  0.315265 |   190654 |


You will note that most time is taken where `$n` is 13. You will note that for `$n` in `2`, `3`, `5`, `13` there are no pan-digital solutions so we have to loop through all the 13 digit numbers and reach the 12 digit numbers before we find a solution. **97.6%** of the checks for matching digits are in the case where `$n` is 13 (approximately **97%** of the time in the code).