Reference: LeetCode
Difficulty: Hard

Problem

A move consists of taking a point (x, y) and transforming it to either (x, x+y) or (x+y, y).

Given a starting point (sx, sy) and a target point (tx, ty), return True if and only if a sequence of moves exists to transform the point (sx, sy) to (tx, ty). Otherwise, return False.

From Twitter OA

Note: sx, sy, tx, ty will all be integers in the range [1, 10^9].

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
Input: sx = 1, sy = 1, tx = 3, ty = 5
Output: True
Explanation:
One series of moves that transforms the starting point to the target is:
(1, 1) -> (1, 2)
(1, 2) -> (3, 2)
(3, 2) -> (3, 5)

Input: sx = 1, sy = 1, tx = 2, ty = 2
Output: False

Input: sx = 1, sy = 1, tx = 1, ty = 1
Output: True

Analysis

Brute-Force

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
// Assume sx, sy, tx, ty >= 1
return dfs(sx, sy, tx, ty);
}

private boolean dfs(int x, int y, int tx, int ty) {
if (x > tx || y > ty) {
return false;
}
if (x == tx && y == ty) {
return true;
}
if (dfs(x, x + y, tx, ty)) return true;
if (dfs(x + y, y, tx, ty)) return true;
return false;
}

Time: $O(2^{tx + ty})$, a loose bound found by considering every move as (x, y) -> (x + 1, y) or (x, y) -> (x, y + 1).
Space: $O(tx + ty)$, the size of call stack.

Work Backwards (Naive Variant)

From LeetCode solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//        / (x + y, y)
// (x, y)
// \ (x, x + y)
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
// Assume sx, sy, tx, ty >= 1
while (tx >= sx && ty >= sy) {
if (sx == tx && sy == ty) return true;
if (tx > ty) {
tx -= ty;
} else {
ty -= tx;
}
}
return false;
}

Time: $O(\max{(tx, ty)})$. If say ty = 1, we could do subtraction for tx times.
Space: $O(1)$

Work Backwards (Modulo Variant)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
// Assume sx, sy, tx, ty
while (tx >= sx && ty >= sy) {
if (tx == ty) break; // impossible to move to reach sx, sy, if (tx,ty) != (sx,sy)
if (tx > ty) {
if (ty > sy) tx %= ty;
else return (tx - sx) % ty == 0;
} else {
if (tx > sx) ty %= tx;
else return (ty - sy) % tx == 0;
}
}
return (tx == sx && ty == sy);
}

Time: $O(\log{\max{(tx, ty)}})$
Space: $O(1)$