```python
class Solution:
def minMoves(self, sx: int, sy: int, tx: int, ty: int) -> int:
ans = 0
# 从终点向起点逆向推导
while tx > sx or ty > sy:
# 如果逆向过程中某个坐标小于起点,说明不可能到达
if tx < sx or ty < sy:
return -1
ans += 1
# 处理两个坐标相等的情况
if tx == ty:
# 只有当起始点有一个坐标为0时,才能从(0,k)或(k,0)到达(k,k)
if sx == 0:
tx = 0
elif sy == 0:
ty = 0
else:
return -1
continue
# 保证 tx > ty,便于统一处理
if tx < ty:
tx, ty = ty, tx
sx, sy = sy, sx
# 核心逆向逻辑
if tx > ty * 2:
# 如果 tx 远大于 ty,上一步只能是翻倍操作
if tx % 2 != 0:
return -1
tx //= 2
else:
# 否则上一步是加法操作,减去较小的那个数
tx -= ty
return ans if tx == sx and ty == sy else -1
```
核心思路:逆向思维 + 贪心
这道题正着推导很难,因为每次都有两种选择。但从终点向起点反向推导就会变得非常清晰:
1. 逆向操作的确定性
· 正向操作:(x, y) → (x+y, y) 或 (x, x+y)
· 逆向操作:如果 tx > ty,最后一步只能是:
· 翻倍:(tx//2, ty)(前提是 tx 为偶数,且 tx//2 != ty,但这里直接减半即可)
· 加法:(tx-ty, ty)
2. 贪心优化
当 tx > ty * 2 时,tx 远大于 ty,此时最后一步不可能是加法(因为加法只会增加 ty,不可能让 tx 变得这么大),所以一定是翻倍操作,直接让 tx 减半。
其他情况则用减法还原。
3. 特殊情况处理
· tx == ty 时,只能从 (0, k) 或 (k, 0) 到达,否则无解
· 逆向过程中如果 tx < sx 或 ty < sy,说明走过头了,返回 -1
4. 坐标交换
为了统一处理,始终保证 tx > ty,如果 tx < ty 就交换两个坐标(同时交换起点坐标)。
时间复杂度
O(log(max(tx, ty))),每次循环都会将较大的数大幅缩小(减半或减去较小数),效率极高。
示例验证
```python
sol = Solution()
print(sol.minMoves(1, 1, 3, 5)) # 输出: 4
print(sol.minMoves(1, 1, 2, 2)) # 输出: 3
print(sol.minMoves(2, 1, 3, 7)) # 输出: -1
```