Description
You are given a 0-indexed binary string s and two integers minJump and maxJump. In the beginning, you are standing at index 0, which is equal to ‘0’. You can move from index i to index j if the following conditions are fulfilled:
i + minJump <= j <= min(i + maxJump, s.length - 1), and
s[j] == '0'.
Return true if you can reach index s.length - 1 in s, or false otherwise.
Example 1:
Input: s = "011010", minJump = 2, maxJump = 3
Output: true
Explanation:
In the first step, move from index 0 to index 3.
In the second step, move from index 3 to index 5.
Example 2:
Input: s = "01101110", minJump = 2, maxJump = 3
Output: false
Constraints:
2 <= s.length <= 10^5
s[i] is either '0' or '1'.
s[0] == '0'
1 <= minJump <= maxJump < s.length
Solution
double-side queue
Use a double-side queue to keep track of where we could jump, and enumerate the nums
. When the index
is at the left of jump interval, we continue. When the index
is at the right of the current jump interval, we pop the jump interval to use a more behind interval. When the index
falls into the jump interval, if nums[index] == 0
, we add a jump interval to the queue.
If the queue is empty, we are running out of choices, so return False
.
Time complexity:
o
(
n
)
o(n)
o(n)
Space complexity:
o
(
n
)
o(n)
o(n)
Heap
Use a heap to keep track of all the possible interval we could visit. If the current index is larger than the current smallest range, pop the range. If the current index falls between the current smallest range, we’ll see if we could update the range heap. That is, if the ch
equals to 0
, we would update the heap. If the current index is smaller than the current range, we keep going and do nothing.
In this way, the heap actually denotes all the blocks we could go. So we would return False
if the heap is empty, and return True
if and only if the last ch
is 0
and it falls between the top of the heap.
In the worst scenario, the heap would grow to the height of n
, so the search and pop time complexity would be
o
(
log
n
)
o(\log n)
o(logn), thus the whole time complexity is:
o
(
n
log
n
)
o(n \log n)
o(nlogn)
Space complexity:
o
(
log
n
)
o(\log n)
o(logn)
Sliding Window + DP
We use dp[i]
to denote whether we could reach i
or not. Then the transform equation will be:
d
p
[
i
]
=
any
(
d
p
[
i
−
m
a
x
J
u
m
p
:
i
−
m
i
n
J
u
m
p
]
)
dp[i] = \text{any}(dp[i - maxJump: i - minJump])
dp[i]=any(dp[i−maxJump:i−minJump])
We use pre_sum
to record the sum of dp[i - maxJump: i - minJump]
, when i
increases, all we need to do is minus the left and add the right.
Time complexity:
o
(
n
)
o(n)
o(n)
Space complexity:
o
(
n
)
o(n)
o(n)
Code
double-side queue
class Solution:
def canReach(self, s: str, minJump: int, maxJump: int) -> bool:
queue = collections.deque([(minJump, maxJump)])
index = 1
while index < len(s):
if queue:
if index < queue[0][0]:
index += 1
elif index > queue[0][1]:
queue.popleft()
else:
if s[index] == '0':
if index == len(s) - 1:
return True
queue.append((index + minJump, index + maxJump))
index += 1
else:
return False
return False
Heap
class Solution:
def canReach(self, s: str, minJump: int, maxJump: int) -> bool:
import heapq
jump_range = []
heapq.heappush(jump_range, (minJump, maxJump))
for i, ch in enumerate(s):
while jump_range and i > jump_range[0][1]:
heapq.heappop(jump_range)
if not jump_range:
return False
if jump_range[0][0] <= i <= jump_range[0][1] and ch == '0':
heapq.heappush(jump_range, (minJump + i, maxJump + i))
return True if ch == '0' and jump_range and jump_range[0][0] <= i <= jump_range[0][1] else False
dp + pre_sum
class Solution:
def canReach(self, s: str, minJump: int, maxJump: int) -> bool:
dp = [True] + [False] * (len(s) - 1)
pre_sum = 0
for i in range(minJump, len(s)):
pre_sum = pre_sum + (dp[i - minJump]) - (dp[i - maxJump - 1] if i - maxJump - 1 >= 0 else 0)
dp[i] = pre_sum > 0 and s[i] == '0'
return dp[-1]