class Solution:
    def minKnightMoves(self, x: int, y: int) -> int:
        """ tc O(X*Y)  sc O(X*Y)
        main idea: limit the search on board onto quardrant.  take care of edge case where going to (1,1) from (0,0) takes 2 steps 
        """
        x,y = abs(x),abs(y)
        if x ==1 and y == 1:
            return 2
        dirs = [(1,2),(1,-2),(-1,2),(-1,-2),(2,1),(2,-1),(-2,1),(-2,-1)]
        q  = collections.deque()
        q.append((0,0))
        seen = set()
        seen.add((0,0))
        res = 0 
        while q :
            size = len(q)
            for i in range(size):
                xx,yy = q.popleft()
                if xx == x and yy == y :
                    return res 
                for dx, dy in dirs:
                    nx = xx + dx 
                    ny = yy + dy
                    if (nx,ny) not in seen and nx >= 0 and ny >= 0:
                        seen.add((nx,ny))
                        q.append((nx,ny))
            res += 1 
        return -1 

DFS + MEMO solution

class Solution:
    def minKnightMoves(self, x: int, y: int) -> int:
        """ tc O(X*Y)  sc O(X*Y)
        main idea: move from target to origin as fast as possible + memo  + handling special cases 
        # (1) original (2) x + y == 2 
        """
        cache = {(1,1):2,(0,0):0,(2,0):2, (0,2):2}
        @lru_cache(None)
        def dfs(x,y):
            x,y = abs(x), abs(y)
            if (x,y) in cache: return cache[(x,y)]  
            return min(dfs(x-1,y-2),dfs(x-2,y-1)) + 1 
        return dfs(x,y)