Let's Make the Kangaroo Problem Work: Algebra Instead of a Loop

Two kangaroos, different starting points, different jump distances. Do they ever land on the same spot at the same time? The instinct is to simulate. Four lines of algebra answer it in O(1).

Let's Make the Kangaroo Problem Work: Algebra Instead of a Loop

Here's the problem, in plain terms: two kangaroos sit at different points on a line. The first starts at x1 and jumps v1 metres each time. The second starts at x2 and jumps v2. They jump at the same moment, forever. Do they ever land on the same spot at the same time?

Almost everyone's first instinct is to simulate it. Loop, jump both, compare positions, stop when they match or when you decide it's hopeless.

That works. It's also unnecessary, and the reason it's unnecessary is worth more than the answer.

The equation is hiding in the wording#

"Land on the same spot at the same time" means: after some number of jumps n, both positions are equal.

Write it down literally:

Code
x1 + n·v1 = x2 + n·v2

That's the whole problem, in one line. Now solve for n:

Code
n·v1 − n·v2 = x2 − x1
n·(v1 − v2) = x2 − x1
n = (x2 − x1) / (v1 − v2)

There's no loop in that. There's a division.

And once you have n as a formula, the question changes shape. It's no longer "do they ever meet?" — it's "is n a valid number of jumps?"

A number of jumps has two properties: it's a whole number (a kangaroo can't jump 3.5 times) and it's positive (they can't have met before they started).

Those two properties are the entire solution.

The code#

Kotlin
fun kangaroo(x1: Int, v1: Int, x2: Int, v2: Int): String {
    if (v1 == v2) return if (x1 == x2) "YES" else "NO"

    // x1 + n*v1 = x2 + n*v2
    // n*(v1 - v2) = x2 - x1
    // n = (x2 - x1) / (v1 - v2)

    val gap = x2 - x1
    val speed = v1 - v2

    return if (gap % speed == 0 && gap / speed > 0) "YES" else "NO"
}

Four meaningful lines. O(1) time, O(1) space.

gap % speed == 0 — the division comes out whole. If it doesn't, they cross between jumps and never share a landing spot. This is the check people forget, and it's the one the problem is really testing.

gap / speed > 0 — the meeting is in the future. A negative n means the equation is satisfied by a jump that would have happened before the start.

The guard clause, and why it's separate#

Kotlin
if (v1 == v2) return if (x1 == x2) "YES" else "NO"

If both kangaroos jump the same distance, v1 - v2 is zero, and dividing by it throws. So it has to be handled before the arithmetic.

Logically it's also the only case where the answer doesn't depend on jumping at all: equal speeds means the gap between them never changes. Same start, they're together forever. Different start, they never meet.

HackerRank's constraints guarantee 0 ≤ x1 < x2, so x1 == x2 can never actually happen and that inner branch is unreachable. It's still worth writing — the function shouldn't depend on a constraint that lives in a problem statement rather than in its own signature.

Why gap is always positive, and what that buys#

Because the constraints promise x1 < x2, gap is always positive. That has a consequence worth noticing:

gap / speed > 0 is true exactly when speed > 0 — that is, when v1 > v2.

Which makes intuitive sense. The kangaroo that's behind must be faster, or it never catches up. You could write the condition that way instead:

Kotlin
return if (v1 > v2 && gap % speed == 0) "YES" else "NO"

Same result, and arguably clearer about the physical situation. I'd keep the division version, because it survives a change to the constraints that the v1 > v2 version wouldn't — but knowing why both work is the actual understanding.

The part that transfers#

The kangaroos don't matter. What matters is the move: before writing a loop, check whether the question is an equation.

A surprising number of "easy" problems are algebra wearing a costume:

  • Two things moving at constant rates → solve for when their positions are equal
  • "How many steps until X" → often a closed form, not an iteration
  • Anything with a fixed stride over a range → division and a remainder

The simulation instinct isn't wrong, and it's a perfectly good way to check your formula. But reaching for it first means you never find out the problem was one line of algebra.

In an interview that difference is visible. Simulating shows you can code. Deriving shows you looked at the problem before you started typing.

Wrapping up#

Write the condition down as an equation. Solve for the unknown. Then ask what makes the answer valid rather than merely real — usually "whole number" and "positive".

Two checks, no loop, O(1).

Next in this series: another problem where the loop everyone writes is hiding a formula.

Until then, let's make this work.

Keep reading

More breakdowns

System Design

Let's Make Three-Tier Architecture Work: Layers, Sync vs Async, and Statelessness

Presentation, domain, data. The oldest diagram in system design, and still the first one you should draw — because it decides what you can scale, what you can swap, and where your state is allowed to live.

· 5 min read
System Design

Let's Make System Design Work: What It Actually Is

System design is drawing how a system is — architecture, components, modules, interfaces and flows. Here's what you're really being assessed on, and why half the scorecard has nothing to do with the diagram.

· 5 min read
Android Architecture

Let's Make SOLID Work: The Principles and Patterns Behind Android Architecture

AsyncTask died, Fragments were rewritten twice, XML gave way to Compose. What survived every migration was the shape of the code underneath. Here are the five principles and nine patterns that decide it.

· 6 min read