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:
  - greedy

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 10<sup>9</sup>, 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 2<sup>0</sup> = 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)`

    &nbsp;

    **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)

    &nbsp;

    **Step 3: Return the result**

    - If the GCD is a power of 2, return `true`
    - Otherwise, return `false`

    &nbsp;

    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 10<sup>9</sup> 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` (2<sup>0</sup>) 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.
