Java BFS + PriorityQueue solution with comments
\nclass Solution {\n    int[][] dirs = {{0,1}, {0, -1}, {1, 0}, {-1, 0}};\n    public int cutOffTree(List<List<Integer>> forest) {\n        // Sort trees by hei
```\nclass Solution {\n    int[][] dirs = {{0,1}, {0, -1}, {1, 0}, {-1, 0}};\n    public int cutOffTree(List<List<Integer>> forest) {\n        // Sort trees by height\n        PriorityQueue<int[]> pq = new PriorityQueue<int[]>( new Comparator<int[]>(){\n            public int compare(int[] p1, int[] p2){\n                return p1[2] - p2[2];\n            }\n        });\n\n        // Add trees in the pq\n        for (int r = 0; r < forest.size(); ++r) \n            for (int c = 0; c < forest.get(0).size(); ++c) {\n                int height = forest.get(r).get(c);\n                if (height >0) pq.add(new int[]{r, c, height});\n            }\n        \n        int last_i = 0, last_j = 0;\n        int result = 0;\n        \n        // Visit shorter trees first\n        while (!pq.isEmpty()){\n            int[] new_step = pq.poll();\n            int step = bfs(forest, last_i, last_j, new_step[0], new_step[1]);\n            if (step == -1) return -1;\n            result += step;\n            last_i = new_step[0];\n            last_j = new_step[1];\n        }\n        return result;\n            \n    }\n    \n    // Using BFS to record shortest dist between two trees\n    private int bfs(List<List<Integer>> forest, int start_i, int start_j, int end_i, int end_j){\n        \n        Queue<int[]> queue = new LinkedList();\n        int m = forest.size(), n = forest.get(0).size();\n        boolean[][] visited = new boolean[m][n];\n        \n        queue.add(new int[]{start_i, start_j});\n        int level = 0;\n        while(!queue.isEmpty()){\n            int size = queue.size();\n            for (int i=0; i<size; i++){\n                int[] curr = queue.poll();\n\t\t\t\t// Target is found. Return the level of BFS traversal as steps\n                if (curr[0] == end_i && curr[1] == end_j)\n                    return level;\n                for (int j=0; j<4; j++){\n                    int next_i = curr[0]+dirs[j][0];\n                    int next_j = curr[1]+dirs[j][1];\n                    if (inBounds(forest, next_i , next_j) && ! visited[next_i][next_j]){\n                        visited[next_i][next_j] = true;\n                        queue.offer(new int[]{ next_i, next_j});\n                    }\n                }\n            }\n            level++;\n        }\n        return -1;\n    }\n    \n    // Return false if out of forest or meet obstacles\n    private boolean inBounds(List<List<Integer>> forest, int i, int j){\n        return (i >=0 && i<=forest.size()-1 && j >=0 && j<=forest.get(0).size()-1 && forest.get(i).get(j) != 0);\n    }\n    \n}\n```
[]