题目地址:
https://leetcode.com/problems/reaching-points/
给定一个数对 ( x , y ) (x,y) (x,y),每走一步可以到达 ( x + y , y ) (x+y,y) (x+y,y)或者 ( x , x + y ) (x,x+y) (x,x+y),再给定一个目标数对,问从初始数对出发能否走到目标数对。题目保证 x x x和 y y y都是正整数。
如果start和target相等,那直接返回true。否则对于某个
(
x
,
y
)
(x,y)
(x,y),一定有
x
≠
y
x \ne y
x=y,因为要到达
(
x
,
x
)
(x,x)
(x,x),其上一步必然是
(
0
,
x
)
(0,x)
(0,x)或者
(
x
,
0
)
(x,0)
(x,0),与
x
x
x是正数矛盾。而若
x
>
y
x>y
x>y,则上一步一定是
(
x
−
y
,
y
)
(x-y,y)
(x−y,y),否则上一步一定是
(
x
,
y
−
x
)
(x, y-x)
(x,y−x)。如此逆推回去,看看能不能推到start即可。
注意到这里可以进行一点优化。如果当
x
>
y
x>y
x>y,我们需要验证
(
x
−
y
,
y
)
,
(
x
−
2
y
,
y
)
.
.
.
,
(
x
−
k
y
,
y
)
(x-y,y),(x-2y,y)...,(x-ky,y)
(x−y,y),(x−2y,y)...,(x−ky,y)(其中
x
−
(
k
−
1
)
y
>
y
x-(k-1)y>y
x−(k−1)y>y但
x
−
k
y
<
y
x-ky<y
x−ky<y)是否等于start,我们也可以这么做:求
(
t
x
%
t
y
,
t
y
)
(tx\%ty, ty)
(tx%ty,ty),然后判断sy == ty
和(sx - tx % ty) % ty == 0
,这两者的等价性非常显然。优化后的代码如下:
public class Solution {
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
if (sx == tx && sy == ty) {
return true;
}
while (sx <= tx && sy <= ty) {
if (tx > ty) {
tx %= ty;
} else {
ty %= tx;
}
if (sx == tx && (sy - ty) % sx == 0) {
return true;
}
if (sy == ty && (sx - tx) % sy == 0) {
return true;
}
}
// 如果跳出循环了,说明sx > tx或者sy > ty,这就不可能再达到了,返回false
return false;
}
}
时间复杂度 O ( log min ( t x , t y ) ) O(\log \min(tx,ty)) O(logmin(tx,ty)),空间 O ( 1 ) O(1) O(1)。
时间复杂度证明:
很显然求
(
t
x
,
t
y
)
(tx,ty)
(tx,ty)的最大公约数的步数可以作为时间复杂度的一个上界。先证明,如果求
a
a
a和
b
b
b的最大公约数的步数为
n
n
n,且
a
>
b
>
0
a>b>0
a>b>0,则最小的
a
a
a和
b
b
b分别是
F
n
+
2
F_{n+2}
Fn+2和
F
n
+
1
F_{n+1}
Fn+1(这里的意思是,需要步数为
n
n
n的所有数对里,
b
b
b最小是
F
n
+
1
F_{n+1}
Fn+1,然后对于这个
b
b
b,
a
a
a最小可以取
F
n
+
2
F_{n+2}
Fn+2),其中
F
n
F_n
Fn为斐波那契数,
F
1
=
F
2
=
1
F_1=F_2=1
F1=F2=1,
F
n
=
F
n
−
1
+
F
n
−
2
F_n=F_{n-1}+F_{n-2}
Fn=Fn−1+Fn−2。数学归纳法,如果只需要一步,此时余数为
0
0
0,所以
a
=
2
=
F
3
a=2=F_3
a=2=F3,
b
=
1
=
F
2
b=1=F_2
b=1=F2,成立。假设对需要
k
k
k步的时候也成立,当需要
k
+
1
k+1
k+1步的时候,第一步为
a
=
b
q
0
+
r
0
a=bq_0+r_0
a=bq0+r0,第二步为
b
=
r
0
q
1
+
r
1
b=r_0q_1+r_1
b=r0q1+r1,所以
b
b
b最小是
F
k
+
2
F_{k+2}
Fk+2,
r
0
r_0
r0最小是
F
k
+
1
F_{k+1}
Fk+1,而最小的
a
a
a在
q
0
=
1
q_0=1
q0=1时取到,所以
a
a
a最小是
F
k
+
3
F_{k+3}
Fk+3。
由上可知,而斐波那契数 F n F_n Fn与 n n n的关系是个对数的关系,所以时间复杂度为 O ( log min ( t x , t y ) ) O(\log \min(tx,ty)) O(logmin(tx,ty))。