This is my response to The Weekly Challenge #397.
Input: @arr = (1, 2, 4, 5, 6)
Output: 7
Average: (1 + 2 + 4 + 5 + 6) / 5 = 3.6
We need the smallest positive integer absent from nums that is strictly
greater than 3.6.
The positive integers greater than 3.6 are 4, 5, 6, 7, ....
4 is in the given array.
5 is in the given array.
6 is in the given array.
7 is not in.
Example 2:
Input: @arr = (-5, -2, -1, 3)
Output: 1
Average: (-5 -2 -1 + 3) / 4 = -1.25
We need the smallest absent positive integer strictly greater than -1.25.
Positive integers are 1, 2, 3, 4, ... (all are strictly greater than
-1.25).
1 is positive and absent from the given array.
Example 3:
Input: @arr = (1, 2, 3)
Output: 4
Average: (1 + 2 + 3) / 3 = 2.0
We need an integer strictly greater than 2.0.
3 is in the given array.
4 is not in.
Example 4:
Input: @arr = (2, 3, 7, 8)
Output: 6
Average: (2 + 3 + 7 + 8) / 4 = 5.0
We need an integer strictly greater than 5.0.
6 is not in the given array.
Example 5:
Input: @arr = (1, 1, 1, 10)
Output: 4
Average: (1 + 1 + 1 + 10) / 4 = 3.25
Positive integers strictly greater than 3.25: 4, 5, 6, ...
4 is not in the given array.
#! /usr/bin/env raku
unit sub MAIN (*@arr where @arr.elems > 0 && all(@arr) ~~ Int,
:v(:$verbose));
my $average = @arr.sum / @arr.elems;
my %seen = @arr.map: * => 1;
my $n = max($average.Int + 1, 1);
say ": Average is $average" if $verbose;
while %seen{$n}
{
say ": $n is in the array" if $verbose;
$n++;
}
say ": $n is not in the array" if $verbose;
say $n;
[3] At least one element, and integers only.
[6] Get the avarage. Note that it may not be an integer.
[7] A hash with the values from the input as keys, for easy element lookup (in the traditional way; we could have used a Set instead).
[8] Get the first integer value higher than the average ($average.Int + 1max(.., 1)
[12] As long as the target value is present in the input,
[16] increse it.
[20] Print the result.
Running it:
$ ./absent-smallest-positive 1 2 4 5 6
7
$ ./absent-smallest-positive -- -5 -2 -1 3
1
$ ./absent-smallest-positive 1 2 3
4
$ ./absent-smallest-positive 2 3 7 8
6
$ ./absent-smallest-positive 1 1 1 10
4
Looking good.
With verbose mode:
$ ./absent-smallest-positive -v 1 2 4 5 6
: Average is 3.6
: 4 is in the array
: 5 is in the array
: 6 is in the array
: 7 is not in the array
7
$ ./absent-smallest-positive -v -- -5 -2 -1 3
: Average is -1.25
: 1 is not in the array
1
$ ./absent-smallest-positive -v 1 2 3
: Average is 2
: 3 is in the array
: 4 is not in the array
4
$ ./absent-smallest-positive -v 2 3 7 8
: Average is 5
: 6 is not in the array
6
$ ./absent-smallest-positive -v 1 1 1 10
: Average is 3.25
: 4 is not in the array
4
Input: @arr = (3, 6, 12)
Output: (3, 6, 12)
Decimal 3 = Binary 11 -> reverse is also same 11 = Decimal 3
Decimal 6 = Binary 110 -> reverse 011 = Decimal 3
Decimal 12 = Binary 1100 -> 0011 = Decimal 3
All three elements have the same binary reflection (3).
Since they tie, they are sorted by their original values in ascending
order: (3, 6, 12).
Example 2:
Input: @arr = (1, 2, 4, 8)
Output: (1, 2, 4, 8)
Decimal 1 = Binary 1 -> reverse is also same 1 = Decimal 1
Decimal 2 = Binary 10 -> reverse is 01 = Decimal 1
Decimal 4 = Binary 100 -> reverse 001 = Decimal 1
Decimal 8 = Binary 1000 -> reverse is 0001 = Decimal 1
All elements reflect to 1. Tie-breaking by original value yields
(1, 2, 4, 8).
Example 3:
Input: @arr = (7, 8, 9, 10)
Output: (8, 10, 7, 9)
Decimal 8 = Binary 1000 -> reverse 0001 = Decimal 1
Decimal 9 = Binary 1001 -> reverse 1001 = Decimal 9
Decimal 10 = Binary 1010 -> reverse 0101 = Decimal 5
Decimal 7 = Binary 111 -> reverse 111 = Decimal 7
Binary reflections:
8 -> 1
9 -> 9
10 -> 5
7 -> 7
Sorting by reflection values (1, 5, 7, 9) gives original elements
(8, 10, 7, 9).
Example 4:
Input: @arr = (5, 9, 15, 17)
Output: (5, 9, 15, 17)
Decimal 5 = Binary 101 -> reverse 101 = Decimal 5
Decimal 9 = Binary 1001 -> reverse 1001 = Decimal 9
Decimal 15 = Binary 1111 -> reverse 1111 = Decimal 15
Decimal 17 = Binary 10001 -> reverse 10001 = Decimal 17
All numbers are binary palindromes, so their reflections match their original decimal values (5, 9, 15, 17),
leaving the array order unchanged.
Example 5:
Input: @arr = (11, 13, 14, 19)
Output: (14, 13, 11, 19)
Decimal 11 = Binary 1011 -> reverse 1101 = Decimal 13
Decimal 13 = Binary 1101 -> reverse 1011 = Decimal 11
Decimal 14 = Binary 1110 -> reverse 0111 = Decimal 7
Decimal 19 = Binary 10011 -> reverse 11001 = Decimal 25
Reflections:
14 -> 7
13 -> 11
11 -> 13
19 -> 25
Sorted by reflection values (7, 11, 13, 25) yields (14, 13, 11, 19).
#! /usr/bin/env raku
unit sub MAIN (*@arr where @arr.elems > 0 && all(@arr) ~~ UInt,
:v(:$verbose));
my @result = @arr.sort: { reflect($_), $_ };
if $verbose
{
for @arr -> $n
{
my $bin = $n.base(2);
say ": $n -> $bin -> { $bin.comb.reverse.join } \
> { reflect($n) }";
}
}
say "({ @result.join(", ") })";
sub reflect(Int $n)
{
$n.base(2).flip.parse-base(2);
}
[3] I think it is fair to narrow down the input values to unsigned integers. Negative integers are not really something we can represent in binary, without trickery (i.e. keeping the sign - or using two's complement in combination with a fixed length).
[6] Sort the values by the binary reflection, and then by the value itself if the former are identical.
[18] Print the result.
[20] Procedure returning the binary reflection.
[22]
Convert the input to binary (base), flip the binary value
(flip), and finally convert it back to decimal (parse-base).
See docs.raku.org/routine/base for more information about base.
See docs.raku.org/routine/flip for more information about flip.
See docs.raku.org/routine/parse-base for more information about parse-base.
Running it:
$ ./binary-reflection 3 6 12
(3, 6, 12)
$ ./binary-reflection 1 2 4 8
(1, 2, 4, 8)
$ ./binary-reflection 7 8 9 10
(8, 10, 7, 9)
$ ./binary-reflection 5 9 15 17
(5, 9, 15, 17)
$ ./binary-reflection 11 13 14 19
(14, 13, 11, 19)
Looking good.
With verbose mode:
$ ./binary-reflection -v 3 6 12
: 3 -> 11 -> 11 -> 3
: 6 -> 110 -> 011 -> 3
: 12 -> 1100 -> 0011 -> 3
(3, 6, 12)
$ ./binary-reflection -v 1 2 4 8
: 1 -> 1 -> 1 -> 1
: 2 -> 10 -> 01 -> 1
: 4 -> 100 -> 001 -> 1
: 8 -> 1000 -> 0001 -> 1
(1, 2, 4, 8)
$ ./binary-reflection -v 7 8 9 10
: 7 -> 111 -> 111 -> 7
: 8 -> 1000 -> 0001 -> 1
: 9 -> 1001 -> 1001 -> 9
: 10 -> 1010 -> 0101 -> 5
(8, 10, 7, 9)
$ ./binary-reflection -v 5 9 15 17
: 5 -> 101 -> 101 -> 5
: 9 -> 1001 -> 1001 -> 9
: 15 -> 1111 -> 1111 -> 15
: 17 -> 10001 -> 10001 -> 17
(5, 9, 15, 17)
$ ./binary-reflection -v 11 13 14 19
: 11 -> 1011 -> 1101 -> 13
: 13 -> 1101 -> 1011 -> 11
: 14 -> 1110 -> 0111 -> 7
: 19 -> 10011 -> 11001 -> 25
(14, 13, 11, 19)
And that's it.