Minimum Moves to Reach Target with Rotations

In an n*n grid, there is a snake that spans 2 cells and starts moving from the top left corner at (0, 0) and (0, 1). The grid has empty cells represented by zeros and blocked cells represented by ones. The snake wants to reach the lower right corner at (n-1, n-2) and (n-1, n-1).

In one move the snake can:

Return the minimum number of moves to reach the target.

If there is no way to reach the target, return -1.

 

Example 1:

Input: grid = [[0,0,0,0,0,1],
               [1,1,0,0,1,0],
               [0,0,0,0,1,1],
               [0,0,1,0,1,0],
               [0,1,1,0,0,0],
               [0,1,1,0,0,0]]
Output: 11
Explanation:
One possible solution is [right, right, rotate clockwise, right, down, down, down, down, rotate counterclockwise, right, down].

Example 2:

Input: grid = [[0,0,1,1,1,1],
               [0,0,0,0,1,1],
               [1,1,0,0,0,1],
               [1,1,1,0,0,1],
               [1,1,1,0,0,1],
               [1,1,1,0,0,0]]
Output: 9

 

Constraints:


Solution:

class Solution {
    public int minimumMoves(int[][] grid) {
        int n = grid.length;
        List<Integer> start = Arrays.asList(0, 0, 0, 1);
        List<Integer> end = Arrays.asList(n - 1, n - 2, n - 1, n - 1);
        Deque<List<Integer>> queue = new ArrayDeque();
        Set<List<Integer>> visited = new HashSet();
        queue.offer(start);
        visited.add(start);
        int step = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i ++) {
                List<Integer> curr = queue.poll();
                if (curr.equals(end)) {
                    return step;
                }
                for (List<Integer> next : getNext(grid, curr)) {
                    if (visited.add(next)) {
                        // System.out.println(next);
                        queue.offer(next);
                    }
                }
            }
            step ++;
        }
        return -1;
    }
    
    private List<List<Integer>> getNext(int[][] grid, List<Integer> curr) {
        int n = grid.length;
        List<List<Integer>> result = new ArrayList();
        int i = curr.get(0);
        int j = curr.get(1);
        int x = curr.get(2);
        int y = curr.get(3);
        // move right one cell
        if (i == x && y + 1 < n && grid[x][y + 1] == 0) {
            result.add(Arrays.asList(x, y, x, y + 1));
        }
        // move down one cell
        if (j == y && x + 1 < n && grid[x + 1][y] == 0) {
            result.add(Arrays.asList(x, y, x + 1, y));
        }
        if (i == x && x + 1 < n && grid[i + 1][j] == 0 && grid[x + 1][y] == 0) {
            // clockwise
            result.add(Arrays.asList(i, j, x + 1, j));
            // shift down
            result.add(Arrays.asList(i + 1, j, x + 1, y));
        }
        if (j == y && y + 1 < n && grid[i][j + 1] == 0 && grid[x][y + 1] == 0) {
            // anticlockwise
            result.add(Arrays.asList(i, j, i, y + 1));
            // shift right
            result.add(Arrays.asList(i, j + 1, x, y + 1));
        }
        return result;
    }
}