title: Check if Point Is Reachable slug: check-if-point-is-reachable difficulty: hard leetcode_id: 2543 leetcode_url: https://leetcode.com/problems/check-if-point-is-reachable/ categories: - math patterns: - slug: greedy is_optimal: true function_signature: "def is_reachable(target_x: int, target_y: int) -> bool:" test_cases: visible: - input: { target_x: 6, target_y: 9 } expected: false - input: { target_x: 4, target_y: 7 } expected: true hidden: - input: { target_x: 1, target_y: 1 } expected: true - input: { target_x: 2, target_y: 2 } expected: true - input: { target_x: 1, target_y: 2 } expected: true - input: { target_x: 3, target_y: 3 } expected: false - input: { target_x: 8, target_y: 16 } expected: true - input: { target_x: 5, target_y: 10 } expected: false description: | There exists an infinitely large grid. You are currently at point `(1, 1)`, and you need to reach the point `(targetX, targetY)` using a finite number of steps. In one **step**, you can move from point `(x, y)` to any one of the following points: - `(x, y - x)` - `(x - y, y)` - `(2 * x, y)` - `(x, 2 * y)` Given two integers `targetX` and `targetY` representing the X-coordinate and Y-coordinate of your final position, return `true` *if you can reach the point from* `(1, 1)` *using some number of steps, and* `false` *otherwise*. constraints: | - `1 <= targetX, targetY <= 10^9` examples: - input: "targetX = 6, targetY = 9" output: "false" explanation: "It is impossible to reach (6, 9) from (1, 1) using any sequence of moves, so false is returned." - input: "targetX = 4, targetY = 7" output: "true" explanation: "You can follow the path (1, 1) -> (1, 2) -> (1, 4) -> (1, 8) -> (1, 7) -> (2, 7) -> (4, 7)." explanation: intuition: | This problem initially seems overwhelming — the grid is infinite, the target can be up to 109, and we have four different moves. Simulating all possible paths is clearly impossible. The breakthrough comes from **thinking backwards**. Instead of asking "can we reach `(targetX, targetY)` from `(1, 1)`?", ask "can we reach `(1, 1)` from `(targetX, targetY)` using the **reverse** operations?" The reverse operations are: - `(x, y)` came from `(x, x + y)` — reverse of `(x, y - x)` - `(x, y)` came from `(x + y, y)` — reverse of `(x - y, y)` - `(x, y)` came from `(x / 2, y)` if `x` is even — reverse of `(2 * x, y)` - `(x, y)` came from `(x, y / 2)` if `y` is even — reverse of `(x, 2 * y)` Now notice something remarkable: the first two reverse operations `(x, x + y)` and `(x + y, y)` are exactly the operations in the **Euclidean algorithm** for computing GCD! If we keep applying these operations, we eventually reach `(gcd(x, y), gcd(x, y))`. The last two operations let us **divide by 2** as many times as we want. So starting from `(targetX, targetY)`: 1. We can reduce to `(gcd(targetX, targetY), gcd(targetX, targetY))` using the GCD operations 2. We can then divide by 2 repeatedly to reach `(1, 1)` This only works if `gcd(targetX, targetY)` is a **power of 2** (including 20 = 1). If the GCD has any odd factor greater than 1, we can never eliminate it. approach: | We solve this using **GCD and bit manipulation**: **Step 1: Compute the GCD** - Calculate `g = gcd(targetX, targetY)` using the Euclidean algorithm - This represents the value we must reduce to `(g, g)` before we can reach `(1, 1)`   **Step 2: Check if GCD is a power of 2** - A number is a power of 2 if and only if it has exactly one bit set - Use the classic bit trick: `g & (g - 1) == 0` returns `true` for powers of 2 - Alternatively, check that `g` has no odd factors (continuously divide by 2 until odd)   **Step 3: Return the result** - If the GCD is a power of 2, return `true` - Otherwise, return `false`   The elegance of this solution is that we reduced a seemingly complex pathfinding problem to a simple mathematical property check. common_pitfalls: - title: Attempting BFS/DFS Simulation description: | The instinct to simulate paths using BFS or DFS fails catastrophically here. With coordinates up to 109 and infinite branching possibilities, any simulation approach will either run out of memory or time. The problem *looks* like a graph traversal but is actually a **number theory** problem in disguise. Recognising when to abandon standard algorithms for mathematical insights is key. wrong_approach: "BFS/DFS to explore all reachable states" correct_approach: "Reverse the problem and analyse GCD properties" - title: Missing the Reverse Thinking description: | Working forward from `(1, 1)` is confusing because the state space explodes exponentially. Working backwards from the target is much more tractable because: - Division by 2 shrinks coordinates - The GCD operations have well-understood convergence properties Always consider whether reversing the direction of a reachability problem simplifies it. wrong_approach: "Simulate forward from (1, 1)" correct_approach: "Work backwards from (targetX, targetY)" - title: Incorrectly Checking Powers of 2 description: | Common mistakes when checking if a number is a power of 2: - Forgetting that `1` (20) is a valid power of 2 - Using `n % 2 == 0` which only checks if `n` is even, not a power of 2 - Using floating-point logarithms which have precision issues The bit manipulation trick `n & (n - 1) == 0` is reliable and handles all edge cases (for `n > 0`). wrong_approach: "log2(n) is an integer check" correct_approach: "Bit manipulation: n & (n - 1) == 0" key_takeaways: - "**Reverse the problem**: When forward simulation is intractable, working backwards often reveals structure" - "**Recognise GCD operations**: The operations `(x, x + y)` and `(x + y, y)` are the Euclidean algorithm — this pattern appears in many problems" - "**Powers of 2 and bit tricks**: `n & (n - 1) == 0` is the standard way to check if `n` is a power of 2" - "**Number theory in disguise**: Some problems that look like graph traversal are actually about mathematical invariants" time_complexity: "O(log(min(targetX, targetY))). Computing GCD using the Euclidean algorithm takes logarithmic time." space_complexity: "O(1). We only use a constant number of variables." solutions: - approach_name: GCD Power of 2 Check is_optimal: true code: | from math import gcd def is_reachable(target_x: int, target_y: int) -> bool: # Compute GCD of the target coordinates g = gcd(target_x, target_y) # Check if GCD is a power of 2 # A number is a power of 2 iff it has exactly one bit set # n & (n - 1) clears the lowest set bit; result is 0 only for powers of 2 return g & (g - 1) == 0 explanation: | **Time Complexity:** O(log(min(targetX, targetY))) — GCD computation dominates. **Space Complexity:** O(1) — Only a few integer variables. The key insight is that we can always reach `(gcd(x, y), gcd(x, y))` from `(x, y)` using the reverse GCD operations, and from there we can only reach `(1, 1)` if we can divide by 2 enough times — which requires the GCD to be a power of 2. - approach_name: Iterative Division Check is_optimal: false code: | from math import gcd def is_reachable(target_x: int, target_y: int) -> bool: # Compute GCD of the target coordinates g = gcd(target_x, target_y) # Remove all factors of 2 from GCD while g % 2 == 0: g //= 2 # If only factors of 2, we end up with 1 return g == 1 explanation: | **Time Complexity:** O(log(min(targetX, targetY))) — GCD computation plus at most log(g) divisions. **Space Complexity:** O(1) — Only integer variables used. This approach explicitly removes all factors of 2 from the GCD. If we end up with 1, the original GCD was a power of 2. If we end up with something greater than 1, there was an odd prime factor that we cannot eliminate.