Program to check we can cross river by stones or not in Python

Suppose we have a list of sorted numbers called stones representing the positions of stones on a river that we are trying to cross. To cross the river, we must finish at the last stone. In each step, we can jump (k - 1, k, or k + 1) steps ahead where k is the distance of the last jump. We have to check whether we can cross the river or not.

So, if the input is like stones = [0, 1, 3, 4, 5, 6, 8, 9, 13], then the output will be True. We can start from 0, then jump 1 unit to reach stone 1, then 2 units to reach 3, after that 2 units to reach 5, then 3 units to reach 8, and finally 5 units to reach 13, which is the final destination.

Algorithm Steps

To solve this, we will follow these steps ?

  • start := A[0], end := last element of A
  • A := a set of all unique elements of A
  • Define a function check(). This will take pos:= start, prev:= 0
  • if pos is same as end, then
    • return True
  • for each jump in [prev − 1, prev, prev + 1], do
    • if jump >= 1, then
      • next_pos := jump + pos
      • if next_pos is in A and check(next_pos, jump) is true, then
        • return True
  • return False
  • From the main method call check() and return result

Example

Let us see the following implementation to get better understanding ?

class Solution:
    def solve(self, A):
        start, end = A[0], A[-1]
        A = set(A)
        
        def check(pos=start, prev=0):
            if pos == end:
                return True
            
            for jump in [prev - 1, prev, prev + 1]:
                if jump >= 1:
                    next_pos = jump + pos
                    if next_pos in A and check(next_pos, jump):
                        return True
            return False
        
        return check()

ob = Solution()
stones = [0, 1, 3, 4, 5, 6, 8, 9, 13]
print(ob.solve(stones))

Output

True

How It Works

The algorithm uses recursive backtracking to explore all possible jump sequences. At each stone position, we try three possible jump distances: the previous jump distance minus 1, the same distance, or plus 1. We convert the stones list to a set for O(1) lookup time when checking if a landing position exists.

Alternative Approach with Memoization

For better performance with larger inputs, we can add memoization to avoid recalculating the same states ?

def can_cross_river(stones):
    if not stones or stones[0] != 0:
        return False
    
    stone_set = set(stones)
    end = stones[-1]
    memo = {}
    
    def dfs(pos, last_jump):
        if pos == end:
            return True
        
        if (pos, last_jump) in memo:
            return memo[(pos, last_jump)]
        
        for jump in [last_jump - 1, last_jump, last_jump + 1]:
            if jump > 0:
                next_pos = pos + jump
                if next_pos in stone_set and dfs(next_pos, jump):
                    memo[(pos, last_jump)] = True
                    return True
        
        memo[(pos, last_jump)] = False
        return False
    
    return dfs(0, 0)

# Test the function
stones = [0, 1, 3, 4, 5, 6, 8, 9, 13]
print(can_cross_river(stones))

Output

True

Conclusion

The river crossing problem can be solved using recursive backtracking by exploring all valid jump sequences. Adding memoization improves efficiency by avoiding redundant calculations for the same position and jump distance combinations.

Updated on: 2026-03-25T13:31:26+05:30

436 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements