-
Notifications
You must be signed in to change notification settings - Fork 43
/
frog-jump.py
279 lines (236 loc) · 9.92 KB
/
frog-jump.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
"""
403. Frog Jump
Hard
A frog is crossing a river. The river is divided into some number of units, and at each unit, there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water.
Given a list of stones' positions (in units) in sorted ascending order, determine if the frog can cross the river by landing on the last stone. Initially, the frog is on the first stone and assumes the first jump must be 1 unit.
If the frog's last jump was k units, its next jump must be either k - 1, k, or k + 1 units. The frog can only jump in the forward direction.
Example 1:
Input: stones = [0,1,3,5,6,8,12,17]
Output: true
Explanation: The frog can jump to the last stone by jumping 1 unit to the 2nd stone, then 2 units to the 3rd stone, then 2 units to the 4th stone, then 3 units to the 6th stone, 4 units to the 7th stone, and 5 units to the 8th stone.
Example 2:
Input: stones = [0,1,2,3,4,8,9,11]
Output: false
Explanation: There is no way to jump to the last stone as the gap between the 5th and 6th stone is too large.
Constraints:
2 <= stones.length <= 2000
0 <= stones[i] <= 231 - 1
stones[0] == 0
stones is sorted in a strictly increasing order.
"""
# V0
# V1
# IDEA : BFS
# https://leetcode.com/problems/frog-jump/discuss/518608/python-BFS
class Solution:
def canCross(self, stones: List[int]) -> bool:
last = stones[-1]
visited = set()
stones = set(stones)
q = [(0,0)]
while q:
for _ in range(len(q)):
node,jump = q.pop(0)
if node == last:
return True
for j in [jump+1,jump-1,jump]:
if j > 0:
if 0<=node+j<=last:
if node+j in stones and ((node+j,j) not in visited):
q.append((node+j,j))
visited.add( (node+j, j) )
return False
# V1'
# https://leetcode-cn.com/problems/frog-jump/
# https://soloveri.gitbook.io/leetcode/dynamic-programming/403-frog-jump
# https://blog.csdn.net/Guo15331092/article/details/78483997
# V1''
# IDEA : Memoization
# https://leetcode.com/problems/frog-jump/discuss/88854/Python-solution-with-detailed-explanation
class Solution(object):
def helper(self, pos, k, stones, N, cache):
if pos > N:
return False
elif pos == N:
return True
elif pos in cache and k in cache[pos]:
return cache[pos][k]
else:
cache.setdefault(pos, {})[k] = False
for jump in (k-1, k, k+1):
if jump > 0 and (pos+jump) in stones:
if self.helper(pos+jump, jump, stones, N, cache):
cache[pos][k] = True
return True
return False
def canCross(self, stones):
"""
:type stones: List[int]
:rtype: bool
"""
return self.helper(stones[0], 0, set(stones), stones[-1], {})
# V1'''
# IDEA : DFS
# https://leetcode.com/problems/frog-jump/discuss/511679/Python-by-DFS-DP-w-Comment
class Solution(object):
def canCross(self, stones):
# total number of valid jump index
n = len(stones)
# valid jump index
stone_set = set(stones)
# record of visited status
visited = set()
# source stone index, destination stone index
source, destination = stones[0], stones[n-1]
# ----------------------------------------
def frog_jump( cur_idx, cur_step):
# Compute current position
cur_move = cur_idx + cur_step
## Base cases:
if (cur_step <= 0) or (cur_move not in stone_set) or ( (cur_idx, cur_step) in visited ):
# Reject on backward move
# Reject on invalid move
# Reject on repeated path
return False
elif cur_move == destination:
# Accept on destination arrival
return True
## General cases:
# mark current status as visited
visited.add( (cur_idx, cur_step) )
# explore all possible next move
return any( frog_jump(cur_move, cur_step + step_offset) for step_offset in (1, 0, -1) )
# ----------------------------------------
return frog_jump(cur_idx=source, cur_step=1)
# V1''''
# IDEA : DP bottom up
# https://leetcode.com/problems/frog-jump/discuss/223586/Python-solution
# IDEA :
# Use a dictionary dic which maps the position of a stone in stones to the set of stepsizes that can jump onto the stone. We initialize dic = {0:{0}}, meaning that we start with the stone at position 0. Next, we iterate i over range(len(stones)), and check if stones[i] is in dic, if it is, it means that there are previous jumps that land on this stone, and we can continue jumping ahead, in which case we iterate over all val in dic[stones[i]], and for each val, we can continue jumping ahead with three stepsizes (val-1, val, and val+1). Therefore, we add val-1 to dic[stones[i]+val-1], val to dic[stones[i]+val], and val+1 to dic[stones[i]+val+1]. Finally, we check if stones[-1] is in dic, if it is, we return True; Else we return False.
#
# Time complexity: O(n^2), space complexity: O(n^2).
class Solution:
def canCross(self, stones):
dic = collections.defaultdict(set)
dic[0].add(0)
for i in range(len(stones)):
if stones[i] in dic:
for val in dic[stones[i]]:
if val > 0:
dic[stones[i]+val].add(val)
if val > 1:
dic[stones[i]+val-1].add(val-1)
dic[stones[i]+val+1].add(val+1)
return stones[-1] in dic
# V1'''''
# IDEA : Brute Force (TLE)
# https://leetcode.com/problems/frog-jump/solution/
# JAVA
# public class Solution {
# public boolean canCross(int[] stones) {
# return can_Cross(stones, 0, 0);
# }
# public boolean can_Cross(int[] stones, int ind, int jumpsize) {
# for (int i = ind + 1; i < stones.length; i++) {
# int gap = stones[i] - stones[ind];
# if (gap >= jumpsize - 1 && gap <= jumpsize + 1) {
# if (can_Cross(stones, i, gap)) {
# return true;
# }
# }
# }
# return ind == stones.length - 1;
# }
# }
# V1''''''
# IDEA : BETTER BRUTE FORCE (TLE)
# https://leetcode.com/problems/frog-jump/solution/
# JAVA
# public class Solution {
# public boolean canCross(int[] stones) {
# return can_Cross(stones, 0, 0);
# }
# public boolean can_Cross(int[] stones, int ind, int jumpsize) {
# if (ind == stones.length - 1) {
# return true;
# }
# int ind1 = Arrays.binarySearch(stones, ind + 1, stones.length, stones[ind] + jumpsize);
# if (ind1 >= 0 && can_Cross(stones, ind1, jumpsize)) {
# return true;
# }
# int ind2 = Arrays.binarySearch(stones, ind + 1, stones.length, stones[ind] + jumpsize - 1);
# if (ind2 >= 0 && can_Cross(stones, ind2, jumpsize - 1)) {
# return true;
# }
# int ind3 = Arrays.binarySearch(stones, ind + 1, stones.length, stones[ind] + jumpsize + 1);
# if (ind3 >= 0 && can_Cross(stones, ind3, jumpsize + 1)) {
# return true;
# }
# return false;
# }
# }
# V1''''''
# IDEA : Using Memoization
# https://leetcode.com/problems/frog-jump/solution/
# JAVA
# public class Solution {
# public boolean canCross(int[] stones) {
# int[][] memo = new int[stones.length][stones.length];
# for (int[] row : memo) {
# Arrays.fill(row, -1);
# }
# return can_Cross(stones, 0, 0, memo) == 1;
# }
# public int can_Cross(int[] stones, int ind, int jumpsize, int[][] memo) {
# if (memo[ind][jumpsize] >= 0) {
# return memo[ind][jumpsize];
# }
# for (int i = ind + 1; i < stones.length; i++) {
# int gap = stones[i] - stones[ind];
# if (gap >= jumpsize - 1 && gap <= jumpsize + 1) {
# if (can_Cross(stones, i, gap, memo) == 1) {
# memo[ind][gap] = 1;
# return 1;
# }
# }
# }
# memo[ind][jumpsize] = (ind == stones.length - 1) ? 1 : 0;
# return memo[ind][jumpsize];
# }
# }
# V1'''''''
# IDEA : Using Memoization with Binary Search
# https://leetcode.com/problems/frog-jump/solution/
# JAVA
# public class Solution {
# public boolean canCross(int[] stones) {
# int[][] memo = new int[stones.length][stones.length];
# for (int[] row : memo) {
# Arrays.fill(row, -1);
# }
# return can_Cross(stones, 0, 0, memo) == 1;
# }
# public int can_Cross(int[] stones, int ind, int jumpsize, int[][] memo) {
# if (memo[ind][jumpsize] >= 0) {
# return memo[ind][jumpsize];
# }
# int ind1 = Arrays.binarySearch(stones, ind + 1, stones.length, stones[ind] + jumpsize);
# if (ind1 >= 0 && can_Cross(stones, ind1, jumpsize, memo) == 1) {
# memo[ind][jumpsize] = 1;
# return 1;
# }
# int ind2 = Arrays.binarySearch(stones, ind + 1, stones.length, stones[ind] + jumpsize - 1);
# if (ind2 >= 0 && can_Cross(stones, ind2, jumpsize - 1, memo) == 1) {
# memo[ind][jumpsize - 1] = 1;
# return 1;
# }
# int ind3 = Arrays.binarySearch(stones, ind + 1, stones.length, stones[ind] + jumpsize + 1);
# if (ind3 >= 0 && can_Cross(stones, ind3, jumpsize + 1, memo) == 1) {
# memo[ind][jumpsize + 1] = 1;
# return 1;
# }
# memo[ind][jumpsize] = ((ind == stones.length - 1) ? 1 : 0);
# return memo[ind][jumpsize];
# }
# }
# V2