11# 913. Cat and Mouse
22# https://leetcode.com/problems/cat-and-mouse/
3- # Dunno
4- # 05 /12/2025
3+ # Minimax, memoization
4+ # 06 /12/2025
55
6-
7- # Note: This is sadly TLE
8- # 70 cases passed
6+ # Draw positions use many more turns, so I use a limit to detect them.
7+ # The issue is that if I put turns in the memo keys, then even winning/losing
8+ # states get recalculated for each turn.
9+ # My solution: I memoize separately the non-draw states (wins/loss)
10+ # without turns. So:
11+ # * wins/losses are instantly recognized,
12+ # * only draws use the turn limit,
13+ # * and the algo becomes much faster.
914class Solution :
1015 def catMouseGame (self , graph ) -> int :
1116 from functools import cache
1217 MOUSE_WINS = 1
1318 CAT_WINS = 2
1419 DRAW = 0
1520 REFUGE = 0
16- limit = 4 * len (graph )
21+ MAX_TURNS = 4 * len (graph )
1722
18- def wins (isCat ):
23+ def win (isCat ):
1924 if isCat : return CAT_WINS
20- else :
21- return MOUSE_WINS
25+ else : return MOUSE_WINS
2226
23- @cache
27+ # Separate memory for non-draw states (wins/losses)
28+ # This caches without turns
29+ helper = {}
30+
31+ @cache #Caches all
2432 def solve (mouse = 1 , cat = 2 , isCat = False , turns = 0 ):
33+ helperKey = (mouse , cat , isCat )
2534 if mouse == cat : return CAT_WINS
2635 if mouse == REFUGE : return MOUSE_WINS
27- if turns >= limit : return DRAW
36+
37+ # Turn limit forces to detect draws
38+ if turns >= MAX_TURNS : return DRAW
39+
40+ # Check helper for previous wins/losses
41+ if helperKey in helper :
42+ return helper [helperKey ]
2843
44+ # Explore all possible moves for current player
2945 newMouse = mouse
3046 newCat = cat
3147 foundDraw = False
3248 for nxt in graph [cat if isCat else mouse ]:
3349 if isCat :
34- if nxt == 0 : continue
50+ if nxt == REFUGE : continue # Cat cannot enter refuge
3551 newCat = nxt
3652 else :
3753 newMouse = nxt
3854 res = solve (newMouse , newCat , not isCat , turns + 1 )
39- if res == wins (isCat ):
55+ # If current player finds a winning move, takes it
56+ if res == win (isCat ):
57+ helper [helperKey ] = res
4058 return res
41-
59+ # Track if there is at least one draw
4260 if res == DRAW :
4361 foundDraw = True
44-
62+
63+ # No wins here
64+ # If found at least one draw, choose draw
4565 if foundDraw :
4666 return DRAW
4767
48- return wins (not isCat )
68+ # No wins or draws found, opponent wins
69+ helper [helperKey ] = win (not isCat )
70+ return win (not isCat )
4971
5072 return solve ()
0 commit comments