LeetCode1030. 距离顺序排列矩阵单元格

给出 R 行 C 列的矩阵,其中的单元格的整数坐标为 (r, c),满足 0 <= r < R 且 0 <= c < C。
另外,我们在该矩阵中给出了一个坐标为 (r0, c0) 的单元格。
返回矩阵中的所有单元格的坐标,并按到 (r0, c0) 的距离从最小到最大的顺序排,其中,两单元格(r1, c1) 和 (r2, c2) 之间的距离是曼哈顿距离,|r1 - r2| + |c1 - c2|。(你可以按任何满足此条件的顺序返回答案。)
输入:R = 1, C = 2, r0 = 0, c0 = 0
输出:[[0,0],[0,1]]
解释:从 (r0, c0) 到其他单元格的距离为:[0,1]
输入:R = 2, C = 2, r0 = 0, c0 = 1
输出:[[0,1],[0,0],[1,1],[1,0]]
解释:从 (r0, c0) 到其他单元格的距离为:[0,1,1,2]
[[0,1],[1,1],[0,0],[1,0]] 也会被视作正确答案。

new一个二维数组,将其初始化为单元格,最后将其排序

class Solution {
    public int[][] allCellsDistOrder(int R, int C, int r0, int c0) {
        int[][] ans = new int[R*C][2];
        int count = 0;
        for(int i=0;i<R;i++){
            for(int j =0;j<C;j++){
                ans[count][0] = i;
                ans[count][1] = j;
                count++;
            }
        }
        Arrays.sort(ans, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return (Math.abs(o1[0]-r0) + Math.abs(o1[1]-c0)) - (Math.abs(o2[0]-r0) + Math.abs(o2[1]-c0));
            }
        });
        return ans;

    }
}

怎么优化?我们知道排序浪费时间,那我们就不进行排序,实际在枚举所有点时,我们可以直接按照哈曼顿距离分桶。这样我们就可以实现线性的桶排序。

class Solution {
    public int[][] allCellsDistOrder(int R, int C, int r0, int c0) {
    	//桶的大小,因为r0的左边和右边,c0的上边和下边,其实曼哈顿距离大小一致,所以桶的大小应该是两者最大值相加。
        int maxDist = Math.max(r0, R - 1 - r0) + Math.max(c0, C - 1 - c0);
        List<List<int[]>> bucket = new ArrayList<List<int[]>>();
        for (int i = 0; i <= maxDist; i++) {
            bucket.add(new ArrayList<int[]>());
        }

        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                int d = dist(i, j, r0, c0);
                bucket.get(d).add(new int[]{i, j});
            }
        }
        int[][] ret = new int[R * C][];
        int index = 0;
        for (int i = 0; i <= maxDist; i++) {
            for (int[] it : bucket.get(i)) {
                ret[index++] = it;
            }
        }
        return ret;
    }

    public int dist(int r1, int c1, int r2, int c2) {
        return Math.abs(r1 - r2) + Math.abs(c1 - c2);
    }
}

BFS,用visit数组+队列实现,要注意,二维数组使用BFS要使用两个一维数组

int[] dx = new int[]{-1, 1, 0, 0};
int[] dy = new int[]{0, 0, -1, 1};
class Solution {
    public int[][] allCellsDistOrder(int R, int C, int r0, int c0) {
        int[] dx = new int[]{-1, 1, 0, 0};
        int[] dy = new int[]{0, 0, -1, 1};
        int[][] res = new int[R*C][2];
        int idx = 0;
        boolean[][] visited = new boolean[R][C];
        Queue<int[]> queue = new ArrayDeque<>();
        queue.offer(new int[]{r0, c0});
        visited[r0][c0] = true;
        while(!queue.isEmpty()){
            int[] tmp = queue.poll();
            res[idx][0] = tmp[0];
            res[idx++][1] = tmp[1];
            for(int i=0; i<4; i++){
                int x = tmp[0] + dx[i], y = tmp[1] + dy[i];
                if(x >= 0 && x < R && y >= 0 && y < C && !visited[x][y]){
                    visited[x][y] = true;
                    queue.offer(new int[]{x, y});
                }
            }
        }
        return res;
    }
}

主要是桶排序和BFS,其余可以自行理解。

你会发现,可以利用几何的方法,进行赋值,距离为1的点在一个正方形边界上,同样的距离为2也一样(你会发现BFS不香吗?)

在这里插入图片描述

class Solution {
    public int[][] allCellsDistOrder(int R, int C, int r0, int c0) {
        int[][] re = new int[R * C][2];
        re[0][0] = r0;
        re[0][1] = c0;
        int[] dr = {1, 1, -1, -1};
        int[] dc = {1, -1, -1, 1};
        int row = r0;
        int col = c0;
        var cnt = 1;
        while (cnt < R * C) {
            row--;
            for (int i = 0; i < 4; i++) {
                while ((i % 2 == 0 && row != r0) || (i % 2 != 0 && col != c0)) {
                    if (row >= 0 && row < R && col >= 0 && col < C) {
                        re[cnt][0] = row;
                        re[cnt][1] = col;
                        cnt++;
                    }
                    row += dr[i];
                    col += dc[i];
                }
            }
        }
        return re;
    }
}

另一种BFS通过总距离和rowDist和colDist来实现。

class Solution {
    public int[][] allCellsDistOrder(int R, int C, int r0, int c0) {
        int[][] re = new int[R * C][2];
        int dist = 0;
        int cnt = 0;
        int[] factor = {-1, 1};
        while (cnt < R * C) {
        	//总距离dist,从零开始,rowDist从0->dist
            for (int rowDist = 0; rowDist <= dist; rowDist++) {
            	//colDist就是总距离-行距离。
                int colDist = dist - rowDist;
                for (int i = 0; i < 2; i++) {
                	//行距离在r0的基础上+1 或者-1
                    int row = r0 + factor[i] * rowDist;
                    for (int j = 0; j < 2; j++) {
                    	//列距离在c0的基础上+1或者-1
                        int col = c0 + factor[j] * colDist;
                        if (row >= 0 && row < R && col >= 0 && col < C) {
                            re[cnt][0] = row;
                            re[cnt][1] = col;
                            cnt++;
                        }
                        if (colDist == 0) break;
                    }
                    if (rowDist == 0) break;
                }
            }
            dist++;
        }
        return re;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值