距离顺序排列矩阵单元格[阅读理解->问题转换(朴素bfs)->自我进阶(priorityqueue)]

81 阅读2分钟

前言

算法题的训练方面,1-提取,将核心内容提取,联系已学知识;2-问题转换,根据提取的问题个性,进行问题转换解决;3-自我进阶,将一些规则抽象,考虑解决方案。

一、距离顺序排列矩阵单元格

image.png

二、朴素bfs

package everyday.simple;

import java.util.LinkedList;
import java.util.Queue;

// 距离顺序排列矩阵单元格。
public class AllCellsDistOrder {
    // 层序遍历即可,没多一层,距离就会变远。
    public int[][] allCellsDistOrder(int rows, int cols, int rCenter, int cCenter) {
        // 采用队列来进行层遍历。
        Queue<int[]> que = new LinkedList<>();
        que.add(new int[]{rCenter, cCenter});
        // 标记位置已经被访问。
        boolean[][] isMark = new boolean[rows][cols];
        isMark[rCenter][cCenter] = true;
        // 层次遍历,收集每层的坐标。
        int[][] rs = new int[rows * cols][2];
        int idx = 0;
        while (!que.isEmpty()) {
            int[] pos = que.poll();
            int i = pos[0], j = pos[1];
            // 将坐标收集起来。
            rs[idx][0] = i;
            rs[idx++][1] = j;
            // 防止重复访问,做上标记。
            isMark[i][j] = true;
            // 将下一层加入队列。
            for (int[] gap : gaps) {
                int ni = gap[0] + i, nj = gap[1] + j;
                if (ni != -1 && -1 != nj && nj != cols && ni != rows && !isMark[ni][nj]) {
                    que.add(new int[]{ni, nj});
                    // bug1:加入队列时,就应该标记,否则会重复加入。
                    isMark[ni][nj] = true;
                }
            }
        }
        return rs;
    }

    static int[][] gaps = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
    // review:如果不是这么朴素的距离,而是将它抽象,如下一步的距离是下一格的数字之和,则需要用到优先队列,每次取元素O(LogN)
}

总结

1)每天一道算法题,养成勤思考,勤训练的习惯。而且可加强对一类问题的理解,通过不断的排除bug,提升自己的严谨性,考虑问题的全面能力。

2)对于一个算法,最后锻炼到自己的提取问题&问题转换&自我进阶的能力。而这些能力与大量算法题的积累紧密相关。

参考文献

[1] LeetCode 距离顺序排列矩阵单元格