This boomerang coding puzzle may mess with your head

I found this interesting boomerang puzzle that many people could get wrong the first time.

Especially if you ask them to do it in one line! — as we going to do later in this article.

JavaScript
const arr = [4, 9, 4, 6, 3, 8, 3, 7, 5, -5, 5]; console.log(countBoomerangs(arr)); // 3

It’s all about counting the “boomerangs” in a list. Can you do it?

Maybe you first want to do what the hell a boomerang is right?

Okay so it’s like, any section of the list with 3 numbers where the first and last digits repeat: like[1, 2, 1]:

So how many boomerangs can you see in [4, 9, 4, 6, 3, 8, 3, 7, 5, -5, 5]?

It’s 3

  1. [4, 9, 4]
  2. [3, 8, 3]
  3. [5, -5, 5]

So the puzzle is to write an algorithm to find this pattern throughout the list.

But here’s where it gets tricky: The algorithm should also count overlapping boomerangs — like in [1, 5, 1, 5, 1, 5, 1] we have FIVE boomerangs — not two — I even thought it was three at first — no it’s freaking five.

So how do we go about this?

My first instinct is to loop through the list and and then when we get up to 3 items we can do the calculation.

It’s one of those situations where we need to keep track of previous values in the loop at every step of the loop.

So in every loop we’ll have one value for the current item, the previous items, and the one before that.

How do we keep track of all the items?

For the current items it’s super easy of course — it’s just the current iter variable:

JavaScript
countBoomerangs([1, 2, 1, 0, 3, 4, 3]); function countBoomerangs(arr) { let curr; for (item of arr) { curr = item; console.log(`curr: ${curr}`); } }

What about keeping tracking of the previous variable?

We can’t use the current iter variable anymore — we need to store the iter variable from one iteration just before the next one starts.

So what we do — store the value of curr just before the loop ends:

JavaScript
countBoomerangs([1, 2, 1, 0, 3, 4, 3]); function countBoomerangs(arr) { let curr; let prev; for (item of arr) { curr = item; console.log(`curr: ${curr}, prev: ${prev}`); prev = curr; } }

Or we can actually do it at the point just before the next loop starts:

JavaScript
countBoomerangs([1, 2, 1, 0, 3, 4, 3]); function countBoomerangs(arr) { let curr; let prev; for (item of arr) { prev = curr; curr = item; console.log(`curr: ${curr}, prev: ${prev}`); } }

It has to be these two points — either just before the loop starts or just before it ends.

Just before the loop starts really meaning before we update curr to the current variable.

Just before it ends really meaning after we finished using the stale prev variable — before we update it — to be stale again the next iteration — do you get? “Stale” because it’s always going to be out of date, it’s supposed to be.

And what about the previous one before this previous one relative to the current variable? The previous previous variable?

We use the exact same logic — although there’s something you’re going to need to watch out for…

So to track the previous previous variable I need to set prev2 to the stale stale iter variable — if you know what I mean, ha ha…

So like before either at the beginning of the loop like this:

JavaScript
countBoomerangs([1, 2, 1, 0, 3, 4, 3]); function countBoomerangs(arr) { let curr; let prev; let prev2; for (item of arr) { // Stale stale iter variable (stale of the stale) prev2 = prev; // Just stale (one stale) prev = curr; // Before update to current (non-stale) curr = item; console.log(`curr: ${curr}, prev: ${prev}, prev2: ${prev}`); } }

But what about at the end?

We have to maintain the order: prev2->prev->curr — we always need to update prev2‘s to the prev‘s stale value before update prev to curr‘s stale value.

JavaScript
function countBoomerangs(arr) { let curr; let prev; let prev2; for (item of arr) { curr = item; // Stale stale iter variable (stale of the stale) console.log(`curr: ${curr}, prev: ${prev}, prev2: ${prev}`); // Before update to current (non-stale) prev2 = prev; // Just stale (one stale) prev = curr; } }

So finally we’ve been able to track all these 3 variables to check for the boomerang.

Now all that’s left is to make the check in every loop and update a count — pretty straightforward stuff:

JavaScript
function countBoomerangs(arr) { // ... let count = 0; for (item of arr) { prev2 = prev; prev = curr; curr = item; if (prev2 === curr && prev !== curr) { count++; } } return count; }
JavaScript
console.log(countBoomerangs([1, 2, 1, 0, 3, 4, 3])); // 2 console.log(countBoomerangs([0, 0, 5, 8, 5, 2, 1, 2])); // 2

And it automatically works for overlapping boomerangs too:

JavaScript
console.log(countBoomerangs([1, 5, 1, 5, 1, 5, 1])); // 5

But isn’t there an easier way?

I noticed we could have just use a traditional for loop and use the iter counter get the sub-list up to 3 numbers back:

Either this:

JavaScript
function countBoomerangs2(arr) { for (let i = 0; i < arr.length; i++) { const prev2 = arr[i - 2]; const prev = arr[i - 1]; const curr = arr[i]; console.log( `curr: ${curr}, prev: ${prev}, prev2: ${prev}` ); } }

or this:

JavaScript
function countBoomerangs2(arr) { for (let i = 0; i < arr.length; i++) { const [prev2, prev, curr] = arr.slice(i - 2, i + 1); console.log(`curr: ${curr}, prev: ${prev}, prev2: ${prev}`); } }

I’ll add a check for when the iter counter goes up to 3 numbers to avoid the undefined stuff. This would definitely throw a nasty out-of-range error in stricter language like C#.

JavaScript
function countBoomerangs2(arr) { for (let i = 0; i < arr.length; i++) { // ✅ Check length if (arr.length > 2) { const [prev2, prev, curr] = arr.slice(i - 2, i + 1); console.log( } } }

And the comparison will be just as before:

JavaScript
function countBoomerangs2(arr) { let count = 0; for (let i = 0; i < arr.length; i++) { if (arr.length > 2) { const [prev2, prev, curr] = arr.slice(i - 2, i + 1); if (prev2 === curr && prev !== curr) { count++; } } } return count; }

The best part about this alternative is it lets us set up a beautiful one-liner solution with functional programming constructs like JavaScript’s reduce().

JavaScript
function countBoomerangs2(arr) { return arr.reduce( (count, _, i, arr) => arr[i - 2] === arr[i] && arr[i - 1] !== arr[i] ? count + 1 : count, 0 ); }

Short and sweet.

Okay maybe not so short — but now just one single multi-line statement.

Puzzle solved.



Leave a Comment

Your email address will not be published. Required fields are marked *