我的解法:
想通过遍历一遍记录位置可不可达,超时
标准解法:
class Solution:
def canReach(self, s: str, minJump: int, maxJump: int) -> bool:
pre = [1]+[0]*(len(s)-1) #初始化时注意边界条件即pre[0]=1
for j in range(1,len(s)):
dp= s[j]=='0' and j>=minJump and (j<=maxJump or pre[j-minJump]-pre[j-maxJump-1]>=1) #条件1和2必须同时满足,条件3和4满足其中一个
pre[j]=pre[j-1]+dp
return dp
拿到这道题很容易想到一种非常直观的思路:记dp[j]表示下标j是否可达,对于每个下标j,遍历上一步可能的所有位置,即从j-maxJump遍历到j-minJump,只要这些位置中有一个可达,那么dp[j]=True。但由于minJump和maxJump可能差距很大,这样做每个状态的转移就需要O(n)时间,的总时间复杂度能达到O(n^2),以本题的数据范围肯定不允许。注意到寻找j-maxJump到j-minJump之间有没有有效位置,本质上是个区间和问题,即要求sum(dp[j-maxJump:j-minJump+1])>0,而区间和可以通过前缀和来O(1)解决,因此可以用一个数组记录dp数组的前缀和,就不需要O(n)转移了。
由于题目保证起点一定不是障碍,因此dp[0]=True,pre[0]=1。遍历下标j时,dp[j]=True需要满足下列条件:
1.s[j]==‘0’。如果不满足,说明下标j本身就是个障碍,不可达。
2.j>=minJump。只跳1步也至少到minJump的位置,0到minJump之间的所有位置都不可达。
3.j<=maxJump。当满足条件1和2时,如果满足此条件,第一步就可以跳到下标j。
4.j>maxJump,同时sum(dp[j-maxJump:j-minJump+1])>0。这时虽然一步跳不到j,但j-maxJump到j-minJump之间存在可达的位置,因此j也可达。
其中条件1和2必须同时满足,条件3和4需要满足其中一个,条件4可以通过前缀和来判断。
这样实现起来就不会在细节上出错了。最后返回dp[-1]就是答案。事实上我们不需要dp数组,只需要前缀和数组,因为dp[j]并不由dp数组里的元素转移而来。
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://leetcode.cn/problems/jump-game-vii/solution/qian-zhui-he-you-hua-dpp-by-v5qyy4q65w-5xml/