questions C

This commit is contained in:
2025-05-25 10:16:13 +01:00
parent c4662f5001
commit 615e3f1291
85 changed files with 16925 additions and 0 deletions

View File

@@ -0,0 +1,161 @@
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.