题目描述
乍一看,这题目似乎还能理解。但要怎么下手呢,贪心吗,好像行不通,这不是什么最优化的问题,而是一个判断能不能的问题。我沉默了许久,还是没有想出什么好思路,暴力枚举肯定超时。于是,鉴于能力不足,我果断选择——看官方解法。
官方
这里对官方解法做了进一步的解释。
方法一:反向计算
这里官方直接反手一个倒推,啊,根本不和你正面刚,这波就反向操作。我看了,顿时觉得自己一开始想的什么各种算法,都想小丑一样,貌似在动脑筋,其实没有卵用。确实,你从正面去思考,怎么从s达到最终的t,道路太多了,而且就像我前面分析的,也没有什么算法策略可以用。这种情况下,逆向思维的确就是一种优势,一种好的思想。
初看,感觉有点斐波那契的味道,但这不是你来我往,有来有回,而是没有规律随机的加法。用加法的角度看,很多选择,但从目标往回倒,用减法的角度看,就只有一种路可以走了。反之,如果这道题让你判断能不能从t减到s,那么就得从s开始倒推往上加了。
注意到这里面在加的过程中,不可能出现相等的情况,如果x的值加到了y上,那么y更新后必定大于x,所以这个加的过程是此起彼伏的增长,x和y只能增加,不能减小。所以如果反向计算,一个状态的前一个状态(如果有),必定是大的那个数,减去小的那个数。如果出现相等,那么就表示这个状态不能再往回倒推了,只能是一个初始状态。
这里注意加上条件tx > sx 和 ty > sy,直接用while循环书写即可。
这一步做了一个优化。本来一个值的更新,比如说是tx = tx-ty,但如果更新之后还是tx>ty,那么又要执行一遍tx=tx-ty,这样合起来相当于tx = tx - n*ty,直到tx<ty,有没有一种很熟悉的感觉,这不就是取模运算吗:x一直截去y,直到x小于y。所以这里是考虑x比y大很多的情况下,直接省去了中间的重复的减的过程。
这里是跳出了倒推循环做最后判断的时刻。首先我们得明白,跳出循环有几种情况:
-
我们先看最简单的tx=ty,如果出现这种情况,说明(tx,ty)倒推自然结束,与sx和sy无关,那么如果两个坐标不相等,自然是false,这是上面第4种情况。
如果相等就是上面的第1种情况,不过这种情况十分巧合,就是一开始tx=sx且ty=sy, 完全没有经历倒推循环的操作,直接返回true。这种特殊情况也需要考虑,不然就会有且仅有一个测试用例卡着你过不去。 -
然后是剩余的情况,tx和ty中至少有一个(实际上也只能有一个)不大于初始值了。这种情况下,至少是等于初始值才有希望,如果小于初始值直接没戏,false,这也是上面第4种情况。
-
所以在其中一方等于初始值的情况下,这里用tx=sx举例,这时候ty>sy还成立,我们明白此时tx不可以再操作了,所以相让ty到sy,只能用ty去减tx,很自然地可以想到,只有在ty与sy的差值可以整除tx时,才可以让ty顺利倒推回sy,返回true。另一种ty=sy,tx>sx的思路一样,这两种对应上面的第2,3中情况。
java代码
//充分理解官方解法后,对代码做出了尽可能的精简。
class Solution {
public boolean reachingPoints(int sx, int sy, int tx, int ty) {
while(tx>sx && ty>sy && tx!=ty){
if(tx>ty) tx = tx%ty;
else ty = ty%tx;
}
if(tx==sx && ty==sy) return true;
if(tx==sx && ty>sy && (ty-sy)%tx==0) return true;
if(ty==sy && tx>sx && (tx-sx)%ty==0) return true;
return false;
}
}
后记:
还是要好好思考。题目解析读起来还不算难,但怎么想到这个解法就很难。
多做题,多总结还是王道。
一切奇思妙想的算法输出的前提,都是大量做题经验的优质输入。