Dynamic programming solution for cross river algorithm (part 2)
You still have the remnant of the same bug.

Consider the river **.*..*...*....** The last slot exists but is not reachable. Yet you can jump from the penultimate slot to cross the river.

Or consider **.*..*...*....*. The slot just past the end is not reachable but something further to its right is.

This can be dealt with by modifying your code thus:

def can_cross_river(river):
    dp = set()
    dp.add((0,0))
    for i,v in enumerate(river):
        if v != '*':
            continue
        for speed in range(0,i+1):
            if (i-speed, speed) in dp or (i-speed, speed-1) in dp or (i-speed, speed+1) in dp:
                dp.add((i, speed))
                if i+speed+1 &gt;= len(river):
                    return True
    return False