Hard
题目描述
有一个无限大的网格。你当前在点 (1, 1),需要使用有限步数到达点 (targetX, targetY)。
在一步中,你可以从点 (x, y) 移动到以下任一点:
- (x, y - x)
- (x - y, y)
- (2 * x, y)
- (x, 2 * y)
给定两个整数 targetX 和 targetY 分别表示最终位置的 X 坐标和 Y 坐标,如果可以从 (1, 1) 使用某些步骤到达该点,则返回 true,否则返回 false。
示例 1:
输入:targetX = 6, targetY = 9
输出:false
解释:不可能使用任何移动序列从 (1,1) 到达 (6,9),因此返回 false。
示例 2:
输入:targetX = 4, targetY = 7
输出:true
解释:你可以按照路径 (1,1) -> (1,2) -> (1,4) -> (1,8) -> (1,7) -> (2,7) -> (4,7)。
约束条件:
- 1 <= targetX, targetY <= 10^9
解题思路
这道题需要从逆向思考的角度来解决。我们从 (targetX, targetY) 开始,尝试回到 (1, 1)。
根据题目给出的四种移动方式,逆向操作为:
- (x, y) → (x, y + x) 或 (x + y, y)
- (x, y) → (x/2, y) 当 x 为偶数时
- (x, y) → (x, y/2) 当 y 为偶数时
关键观察:前两种操作不会改变 gcd(x, y),而后两种操作可能会改变 gcd。我们需要分析什么时候使用除法操作是最优的。
核心思路:
- 当 x 和 y 都大于 1 且其中一个是偶数时,优先使用除法操作
- 当两个数都是奇数时,使用减法操作(类似辗转相除法)
- 最终目标是到达 (1, 1)
算法步骤:
- 不断对较大的偶数除以 2
- 当两数都是奇数时,用大数减小数
- 重复直到其中一个数变为 1
- 检查剩余的数是否为 2 的幂次
这个问题本质上是判断能否通过 gcd 操作和 2 的幂次操作从目标点回到 (1, 1)。
代码实现
class Solution {
public:
bool isReachable(int targetX, int targetY) {
int gcd_val = gcd(targetX, targetY);
// 检查 gcd 是否只包含因子 2
while (gcd_val % 2 == 0) {
gcd_val /= 2;
}
return gcd_val == 1;
}
private:
int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
};
class Solution:
def isReachable(self, targetX: int, targetY: int) -> bool:
import math
gcd_val = math.gcd(targetX, targetY)
# 检查 gcd 是否只包含因子 2
while gcd_val % 2 == 0:
gcd_val //= 2
return gcd_val == 1
public class Solution {
public bool IsReachable(int targetX, int targetY) {
int gcdVal = GCD(targetX, targetY);
// 检查 gcd 是否只包含因子 2
while (gcdVal % 2 == 0) {
gcdVal /= 2;
}
return gcdVal == 1;
}
private int GCD(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
}
var isReachable = function(targetX, targetY) {
while (targetX % 2 === 0) {
targetX /= 2;
}
while (targetY % 2 === 0) {
targetY /= 2;
}
while (targetX !== targetY) {
if (targetX > targetY) {
targetX -= targetY;
} else {
targetY -= targetX;
}
}
return targetX === 1;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(log(min(targetX, targetY))) |
| 空间复杂度 | O(1) |
时间复杂度主要来自计算 GCD 的过程,以及对 GCD 进行因子 2 的除法操作。空间复杂度为常数级别。