Kurt Peek - 1 year ago 143
Python Question

# How to speed up a recursive algorithm

I'm trying to solve the Hackerrank challenge Game of Stones, a (shortened) problem statement of which is copied below.

I came up with the following solution:

``````# The lines below are for the Hackerrank submission
# T = int(raw_input().strip())
# ns = [int(raw_input().strip()) for _ in range(T)]

T = 8
ns = [1, 2, 3, 4, 5, 6, 7, 10]

legal_moves = [2, 3, 5]

def which_player_wins(n):
if n <= 1:
return "Second"               # First player loses
elif n in legal_moves:
return "First"                # First player wins immediately
else:
next_ns = map(lambda x: n - x, legal_moves)
next_ns = filter(lambda x: x >= 0, next_ns)
next_n_rewards = map(which_player_wins, next_ns)      # Reward for opponent
if any(map(lambda x: x=="Second", next_n_rewards)):            # Opponent enters a losing position
return "First"
else:
return "Second"

for n in ns:
print which_player_wins(n)
``````

The algorithm is essentially the minimax algorithm as it looks one move ahead and then recursively calls the same function. The problem is that in Hackerrank, it is terminating due to timeout:

Indeed, I've noticed that evaluating
`which_player_wins(40)`
already takes ~2 seconds. Any ideas for a faster solution which would not time out?

In other words, keep a global array that stores the results from previous determinations of wins and losses. When you determine for a new value of `n`, rather than recursing all the way to the end, use the previous determinations.
For example, when you get to `n=10`, you see that the first player removing 3 stones leaves 7 stones, which you have already seen as a win for the second player. Therefore, 10 stones is a win for the first player.
I believe that your recursive algorithm would calculate all over again the result for `n=7` rather than using the previous work.