Skip to main content

Breadth First Search

Frog Jump

Problem Statement

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 - 1k, 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 stones is too large.

Video Explanation

Java Code

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

class Solution {
    public boolean canCross(int[] stones) {
        int destination = stones[stones.length - 1];
        
        Map<Integer, Set<Integer>> hashMap = new HashMap<>();
        for(int stone : stones) {
            hashMap.put(stone, new HashSet<>());
        }
        
        hashMap.get(stones[0]).add(1);
        
        for(int i = 0; i < stones.length; i++) {
            int currStonePosition = stones[i];
            for(int jump : hashMap.get(currStonePosition)) {
                int nextPosition = currStonePosition + jump;
                if(nextPosition == destination) {
                    return true;
                }
                if(hashMap.containsKey(nextPosition)) {
                    if(jump - 1 > 0) {
                        hashMap.get(nextPosition).add(jump - 1);
                    }
                    hashMap.get(nextPosition).add(jump);
                    hashMap.get(nextPosition).add(jump + 1);
                }   
            }
        }

        return false;
    }
}

C++ Code

#include<bits/stdc++.h>
using namespace std;

class Solution {
public:
    bool canCross(vector<int>& stones) {
        int destination = stones.back();

        map<int, set<int>> hashMap;
        for (int stone : stones) {
            hashMap[stone] = set<int>();
        }

        hashMap[stones[0]].insert(1);

        for (int i = 0; i < stones.size(); i++) {
            int currStonePosition = stones[i];
            for (int jump : hashMap[currStonePosition]) {
                int nextPosition = currStonePosition + jump;
                if (nextPosition == destination) {
                    return true;
                }
                if (hashMap.find(nextPosition) != hashMap.end()) {
                    if (jump - 1 > 0) {
                        hashMap[nextPosition].insert(jump - 1);
                    }
                    hashMap[nextPosition].insert(jump);
                    hashMap[nextPosition].insert(jump + 1);
                }
            }
        }

        return false;
    }
};

Python Code

from typing import List

class Solution:
    def canCross(self, stones: List[int]) -> bool:

        destination = stones[-1]

        hash_map = dict()
        for stone in stones:
            hash_map[stone] = set()
        
        hash_map[stones[0]].add(1)

        for i in range(len(stones)):
            curr_stone_position = stones[i]
            for jump in hash_map[curr_stone_position]:
                next_position = curr_stone_position + jump
                if next_position == destination:
                    return True
                if next_position in hash_map:
                    if jump - 1 > 0:
                        hash_map[next_position].add(jump - 1)
                    hash_map[next_position].add(jump)
                    hash_map[next_position].add(jump + 1)

        return False

Javascript Code

var canCross = function(stones) {
    let destination = stones[stones.length - 1];

    let hashMap = new Map();
    for (let stone of stones) {
        hashMap.set(stone, new Set());
    }

    hashMap.get(stones[0]).add(1);

    for (let i = 0; i < stones.length; i++) {
        let currStonePosition = stones[i];

        for (let jump of hashMap.get(currStonePosition)) {
            let nextPosition = currStonePosition + jump;

            if (nextPosition === destination) {
                return true;
            }

            if (hashMap.has(nextPosition)) {
                if (jump - 1 > 0) {
                    hashMap.get(nextPosition).add(jump - 1);
                }
                hashMap.get(nextPosition).add(jump);
                hashMap.get(nextPosition).add(jump + 1);
            }
        }
    }

    return false;
};

Go Code

func canCross(stones []int) bool {
	destination := stones[len(stones)-1]

    // In Go, we don't have Set, therefore, we are creating map as set only. struct{} represents an empty struct.
	hashMap := make(map[int]map[int]struct{})
	for _, stone := range stones {
		hashMap[stone] = make(map[int]struct{}) // assigning set
	}

	hashMap[stones[0]][1] = struct{}{}

	for i := 0; i < len(stones); i++ {
		currStonePosition := stones[i]

		for jump := range hashMap[currStonePosition] {
			nextPosition := currStonePosition + jump

			if nextPosition == destination {
				return true
			}

			if _, exists := hashMap[nextPosition]; exists {
				if jump-1 > 0 {
					hashMap[nextPosition][jump-1] = struct{}{}
				}
				hashMap[nextPosition][jump] = struct{}{}
				hashMap[nextPosition][jump+1] = struct{}{}
			}
		}
	}

	return false
}

Complexity Analysis

Time complexity: O(N2)
Space Complexity: O(N2)