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.
For example:
stones = [0,1,3,5,6,8,12,17]
should return true
because 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.
However, stones = [0,1,2,3,4,8,9,11]
should return false
because there is no way to jump to the last stone as the gap between the 5th and 6th stone is too large.
Write a function to determine if the frog can cross the river by landing on the last stone, given the stones' positions.
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.
A brute-force approach would involve exploring all possible jump combinations using recursion. Starting from the first stone, we can try all possible jump lengths (k-1
, k
, k+1
) and recursively check if we can reach the last stone. This approach has exponential time complexity because we may recompute the same subproblems multiple times.
def can_cross_recursive(stones):
def can_cross(current_position, last_jump):
if current_position == stones[-1]:
return True
for next_jump in [last_jump - 1, last_jump, last_jump + 1]:
if next_jump > 0:
next_position = current_position + next_jump
if next_position in stones and next_position > current_position:
if can_cross(next_position, next_jump):
return True
return False
if stones[1] != 1:
return False
return can_cross(1, 1)
We can optimize the solution using dynamic programming. We use a hash map where the keys are the stone positions, and the values are sets of possible jump sizes that can lead to that stone. This allows us to store and reuse the results of subproblems. For each stone, we iterate through the possible jump sizes and check if we can reach the next stone.
def can_cross_dp(stones):
stone_positions = {stone: set() for stone in stones}
stone_positions[0].add(0)
for stone in stones:
for jump_size in stone_positions[stone]:
for next_jump in [jump_size - 1, jump_size, jump_size + 1]:
if next_jump > 0 and stone + next_jump in stone_positions:
stone_positions[stone + next_jump].add(next_jump)
return len(stone_positions[stones[-1]]) > 0
stones
should be sorted in strictly ascending order.def can_cross(stones):
if stones[1] != 1:
return False
stone_positions = {stone: set() for stone in stones}
stone_positions[0].add(0)
for stone in stones:
for jump_size in stone_positions[stone]:
for next_jump in [jump_size - 1, jump_size, jump_size + 1]:
if next_jump > 0 and stone + next_jump in stone_positions:
stone_positions[stone + next_jump].add(next_jump)
return len(stone_positions[stones[-1]]) > 0