Java A* 91% Speed&Mem with Explanations.
If you are not familiar with A search, read this https://www.redblobgames.com/pathfinding/a-star/introduction.html first. It comes in handy with quesitons like 
If you are not familiar with A* search, read this https://www.redblobgames.com/pathfinding/a-star/introduction.html first. It comes in handy with quesitons like this. This question basically boils down to how to effectively search for the next tree to cut down when they are all over the map. A* is great for this while standard BFS may give TLE. A* uses a priorityQueue to achieve its effectiveness.\n\nLet\'s take down the problem into several parts:\n\nPart 1: Count how many trees there are and record their positon and heights with a List.\nPart 2: Check if we can reach all the trees, if not, return -1 here.\nPart 3: Sort the ArrayList in accordance with their height.\nPart 4: Start our A* search and loop it until there is no more tree to cut\nPart 5: Return the result. \n\nThe below is my code for reference\n```\nclass Solution {\n    private static int N;\n    private static int M;\n    private static final int[][] dirs = {{1, 0}, {0, -1}, {0, 1}, {-1, 0}};\n\n    public int cutOffTree(List<List<Integer>> forest) {\n        N = forest.size();\n        M = forest.get(0).size();\n        \n        List<int[]> trees = new ArrayList<>();\n        for (int i = 0; i < N; i++)\n            for (int j = 0; j < M; j++)\n                if (forest.get(i).get(j) > 1)\n                    trees.add(new int[]{i, j, forest.get(i).get(j)});\n\n        if (trees.size() != reachableTrees(forest, 0, 0, new boolean[N][M])) return -1;\n        Collections.sort(trees, Comparator.comparingInt(o -> o[2]));\n\n        int ans = 0;\n        int idx = 0;\n        int pr = 0;\n        int pc = 0;\n        while(idx < trees.size()){\n            int tr = trees.get(idx)[0];\n            int tc = trees.get(idx++)[1];\n            PriorityQueue<int[]> minheap = new PriorityQueue<>(Comparator.comparingInt(o -> o[0]));\n            minheap.offer(new int[]{dist(pr, pc, tr, tc), 0, pr, pc}); // priority, steps, r, c\n            boolean[][] seen = new boolean[N][M];\n            while(!minheap.isEmpty()){\n                int[] cur = minheap.poll();\n                int pri = cur[0];\n                int steps = cur[1];\n                int r = cur[2];\n                int c = cur[3];\n                if (r == tr && c == tc) {ans += steps; break;}\n                seen[r][c] = true;\n\n                for (int[] d : dirs){\n                    int nr = r + d[0];\n                    int nc = c + d[1];\n                    if (nr < 0 || nc < 0 || nr >= N || nc >= M || seen[nr][nc]\n                            || forest.get(nr).get(nc) == 0)\n                        continue;\n                    minheap.offer(new int[]{dist(nr, nc, tr, tc) + steps + 1, steps + 1, nr, nc});\n                }\n            }\n            pr = tr;\n            pc = tc;\n        }\n        return ans;\n    }\n\n    private int reachableTrees(List<List<Integer>> forest, int r, int c, boolean[][] seen){\n        if (r < 0 || r >= N || c < 0 || c >= M || seen[r][c]\n                || forest.get(r).get(c) == 0) return 0;\n\n        seen[r][c] = true;\n\n        return (forest.get(r).get(c) > 1? 1 : 0) \n            + reachableTrees(forest, r + 1, c, seen)\n            + reachableTrees(forest, r - 1, c, seen)\n            + reachableTrees(forest, r, c + 1, seen)\n            + reachableTrees(forest, r, c - 1, seen);\n    }\n\n    private int dist(int x, int y, int dx, int dy){\n        return Math.abs(x - dx) + Math.abs(y - dy);\n    }\n}\n```
['Breadth-First Search', 'Heap (Priority Queue)', 'Java']