403. Frog Jump

Description

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] <= 2^31 - 1

  • stones[0] == 0

Tags

Dynamic Programming, Backtracking

Solution

See Reference for Dynamic Programming solutions.

Here we use the DFS strategy and use a stack to store each state rather than recursion. We define the pair{unit, k} to describe the state, and initialize the states stack with []pair{{3, 2}, {2, 1}, {1, 0}} since the problem requires the first jump must be 1 unit. The goal is return true if we can find a pair whose unit is the last element of the input array. When traverse the stack, we ignore pairs that:

  • k of whom is 0;

  • unit of whom does not exist in the array;

  • have been visited (use a set to record).

The remain states pair{pos.unit + pos.k + i, pos.k + i} (-1 ≤ i ≤ 1) would be pushed into the stack. If the goal cannot be reached before the stack becomes empty, we return false.

Complexity

  • Time complexity: O(n2)O(n^2)

  • Space complexity: O(n2)O(n^2)

Code

func canCross(stones []int) bool {
	if len(stones) < 2 || stones[1] != 1 {
		return false
	}
	// optimization: the frog cannot reach the goal if there exists i that stones[i]-stones[i-1] > i
	for i := 1; i < len(stones); i++ {
		if stones[i]-stones[i-1] > i {
			return false
		}
	}
	unit2idx := map[int]int{}
	for i, u := range stones {
		unit2idx[u] = i
	}
	visited := map[pair]bool{} // remove duplicates
	stack := []pair{{3, 2}, {2, 1}, {1, 0}}
	for len(stack) > 0 {
		pos := stack[len(stack)-1]
		stack = stack[:len(stack)-1]
		if unit2idx[pos.unit] == len(stones)-1 {
			return true
		}
		if pos.k == 0 || unit2idx[pos.unit] == 0 {
			continue
		}
		for i := -1; i <= 1; i++ {
			p := pair{pos.unit + pos.k + i, pos.k + i}
			if !visited[p] {
				visited[p] = true
				stack = append(stack, p)
			}
		}
	}
	return false
}

Reference

Last updated

Was this helpful?