number of boomerangs
10.11.2023 3 min readA boomerang is a V-shaped sequence that is either upright or upside down. Specifically, a boomerang can be defined as: sub-array of length 3, with the first and last digits being the same and the middle digit being different.
Some boomerang examples:
[3, 7, 3], [1, -1, 1], [5, 6, 5]
Be aware that boomerangs can overlap, like so:
[1, 7, 1, 7, 1, 7, 1] // 5 boomerangs (from left to right): [1, 7, 1], [7, 1, 7], [1, 7, 1], [7, 1, 7], and [1, 7, 1]
Slices. We need slices.
crystal
:
def number_of_boomerangs(arr : Array(Int32)) : Int32
count = 0
arr.each_with_index do |_, i|
slice = arr[i..i + 2]
next if slice.size != 3
a, b, c = slice
count += 1 if a == c && a != b
end
return count
end
crystal
lets us create slices even if it goes out of bounds. Not so with nim
:
proc numberOfBoomerangs(s: seq[int]): int =
for i in 0 ..< s.len:
if i + 2 > s.len - 1: break
let slice = s[i .. i + 2]
if slice[0] == slice[2] and slice[0] != slice[1]: result.inc
We have to be a little more careful with indexing - trying to access something that doesn’t exist will throw an indexDefect
in nim
. We also don’t have nice destructuring syntax built-in, unlike crystal
.
raku
:
sub number-of-boomerangs(@a) {
my $c = 0;
for @a.kv -> $i, $_ {
last if Any ~~ any(@a[$i..$i+2]);
my @s = @a[$i..$i+2];
$c++ if @s.head == @s.tail && @s.head != @s[1];
}
$c;
}
More of the same… but different? We could check what i
is, and break out of the loop - instead, we check if any of the elements in the slice are of type Any
. While raku
doesn’t complain about out of bounds errors, it does something unexpected - it goes ahead and creates the slice, but fills it with Any
when there are no more elements left to index.
js
:
function numberOfBoomerangs(arr: number[]): number {
let count = 0;
for (let i = 0; i <= arr.length - 1; i++) {
const slice = arr.slice(i, i + 3);
if (slice.length !== 3) break;
const [a, b, c] = slice;
if (a === c && a !== b) count++;
}
return count;
}
Here, we have to use a c-style loop. While I don’t like these very much (I am very much prone to off-by-one errors), .forEach
doesn’t allow breaking out of the loop.
Anyway, that’s about it. While the core logic for each is largely the same - it’s interesting to see how each language has its own set of idiosyncrasies.