Use this to learn the idea, then write your own version.
123 4import heapq5import itertools6 7 89class Solution(object):10 def slidingPuzzle(self, board):11 """12 :type board: List[List[int]]13 :rtype: int14 """15 def dot(p1, p2):16 return p1[0]*p2[0]+p1[1]*p2[1]17 18 def heuristic_estimate(board, R, C, expected):19 result = 020 for i in xrange(R):21 for j in xrange(C):22 val = board[C*i + j]23 if val == 0: continue24 r, c = expected[val]25 result += abs(r-i) + abs(c-j)26 return result27 28 R, C = len(board), len(board[0])29 begin = tuple(itertools.chain(*board))30 end = tuple(range(1, R*C) + [0])31 expected = {(C*i+j+1) % (R*C) : (i, j)32 for i in xrange(R) for j in xrange(C)}33 34 min_steps = heuristic_estimate(begin, R, C, expected)35 closer, detour = [(begin.index(0), begin)], []36 lookup = set()37 while True:38 if not closer:39 if not detour:40 return -141 min_steps += 242 closer, detour = detour, closer43 zero, board = closer.pop()44 if board == end:45 return min_steps46 if board not in lookup:47 lookup.add(board)48 r, c = divmod(zero, C)49 for direction in ((-1, 0), (1, 0), (0, -1), (0, 1)):50 i, j = r+direction[0], c+direction[1]51 if 0 <= i < R and 0 <= j < C:52 new_zero = i*C+j53 tmp = list(board)54 tmp[zero], tmp[new_zero] = tmp[new_zero], tmp[zero]55 new_board = tuple(tmp)56 r2, c2 = expected[board[new_zero]]57 r1, c1 = divmod(zero, C)58 r0, c0 = divmod(new_zero, C)59 is_closer = dot((r1-r0, c1-c0), (r2-r0, c2-c0)) > 060 (closer if is_closer else detour).append((new_zero, new_board))61 return min_steps62 63 64656667class Solution2(object):68 def slidingPuzzle(self, board):69 """70 :type board: List[List[int]]71 :rtype: int72 """73 def heuristic_estimate(board, R, C, expected):74 result = 075 for i in xrange(R):76 for j in xrange(C):77 val = board[C*i + j]78 if val == 0: continue79 r, c = expected[val]80 result += abs(r-i) + abs(c-j)81 return result82 83 R, C = len(board), len(board[0])84 begin = tuple(itertools.chain(*board))85 end = tuple(range(1, R*C) + [0])86 end_wrong = tuple(range(1, R*C-2) + [R*C-1, R*C-2, 0])87 expected = {(C*i+j+1) % (R*C) : (i, j)88 for i in xrange(R) for j in xrange(C)}89 90 min_heap = [(0, 0, begin.index(0), begin)]91 lookup = {begin: 0}92 while min_heap:93 f, g, zero, board = heapq.heappop(min_heap)94 if board == end: return g95 if board == end_wrong: return -196 if f > lookup[board]: continue97 98 r, c = divmod(zero, C)99 for direction in ((-1, 0), (1, 0), (0, -1), (0, 1)):100 i, j = r+direction[0], c+direction[1]101 if 0 <= i < R and 0 <= j < C:102 new_zero = C*i+j103 tmp = list(board)104 tmp[zero], tmp[new_zero] = tmp[new_zero], tmp[zero]105 new_board = tuple(tmp)106 f = g+1+heuristic_estimate(new_board, R, C, expected)107 if f < lookup.get(new_board, float("inf")):108 lookup[new_board] = f109 heapq.heappush(min_heap, (f, g+1, new_zero, new_board))110 return -1111 112