题目地址
难度: ⭐
题目描述: 给出 R
行 C
列的矩阵,其中的单元格的整数坐标为 (r, c)
,满足 0 <= r < R
且 0 <= c < C
。
另外,我们在该矩阵中给出了一个坐标为 (r0, c0)
的单元格。
返回矩阵中的所有单元格的坐标,并按到 (r0, c0)
的距离从最小到最大的顺序排,其中,两单元格(r1, c1)
和 (r2, c2)
之间的距离是曼哈顿距离,|r1 - r2| + |c1 - c2|
。(你可以按任何满足此条件的顺序返回答案。)
示例1:
1 2 3 输入:R = 1, C = 2, r0 = 0, c0 = 0 输出:[[0,0],[0,1]] 解释:从 (r0, c0) 到其他单元格的距离为:[0,1]
示例2:
1 2 3 4 输入: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]] 也会被视作正确答案。
示例3:
1 2 3 4 输入:R = 2, C = 3, r0 = 1, c0 = 2 输出:[[1,2],[0,2],[1,1],[0,1],[1,0],[0,0]] 解释:从 (r0, c0) 到其他单元格的距离为:[0,1,1,2,2,3] 其他满足题目要求的答案也会被视为正确,例如 [[1,2],[1,1],[0,2],[1,0],[0,1],[0,0]]
提示:
1 <= R <= 100
1 <= C <= 100
0 <= r0 < R
0 <= c0 < C
🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️解题过程🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️🙋♂️
解题过程: 思路:
遍历矩阵,计算每个单元格与(r0,c0)的曼哈顿距离d,然后d作为键,单元格的坐标作为值存到multimap容器中,利用multimap容器的特性:容器中元素按关键字排序,并且允许多个关键字相同。遍历完成得到按曼哈顿距离升序排序的multimap容器,遍历multimap把值依次放到结果中,最后返回。
c++代码: (执行用时176ms,击败17.98%,内存消耗29M,击败15.48%)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution {public : vector <vector <int >> allCellsDistOrder (int R, int C, int r0, int c0) { vector <vector <int >> result; multimap <int ,vector <int >> m; vector <int > v; int d; for (int i=0 ;i<R;++i){ for (int j=0 ;j<C;++j){ v.clear(); v.emplace_back(i); v.emplace_back(j); d=abs (r0-i)+abs (c0-j); m.insert(pair <int ,vector <int >>(d,v)); } } for (auto tmp:m){ result.emplace_back(tmp.second); } return result; } };
💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎官 方 题 解💎💎💎💎💎💎💎💎💎💎💎💎💎💎💎
方法一:直接排序
思路及解法
最容易想到的方法是首先存储矩阵内所有的点,然后将其按照哈曼顿距离直接排序。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution {public : vector <vector <int >> allCellsDistOrder (int R, int C, int r0, int c0) { vector <vector <int >> ret; for (int i = 0 ; i < R; i++) { for (int j = 0 ; j < C; j++) { ret.push_back({i, j}); } } sort(ret.begin(), ret.end(), [=](vector <int >& a, vector <int >& b) { return abs (a[0 ] - r0) + abs (a[1 ] - c0) < abs (b[0 ] - r0) + abs (b[1 ] - c0); }); return ret; } };
复杂度分析
方法二:桶排序
思路及解法
注意到方法一中排序的时间复杂度太高。实际在枚举所有点时,我们可以直接按照哈曼顿距离分桶。这样我们就可以实现线性的桶排序。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution {public : int dist (int r1, int c1, int r2, int c2) { return abs (r1 - r2) + abs (c1 - c2); } vector <vector <int >> allCellsDistOrder (int R, int C, int r0, int c0) { int maxDist = max(r0, R - 1 - r0) + max(c0, C - 1 - c0); vector <vector <vector <int >>> bucket (maxDist + 1 ) ; for (int i = 0 ; i < R; i++) { for (int j = 0 ; j < C; j++) { int d = dist(i, j, r0, c0); vector <int > tmp = {i, j}; bucket[d].push_back(move(tmp)); } } vector <vector <int >> ret; for (int i = 0 ; i <= maxDist; i++) { for (auto &it : bucket[i]) { ret.push_back(it); } } return ret; } };
复杂度分析
方法三:几何法
思路及解法
我们也可以直接变换枚举矩阵的顺序,直接按照曼哈顿距离遍历该矩形即可。
注意到曼哈顿距离相同的位置恰好构成一个斜着的正方形边框,因此我们可以从小到大枚举曼哈顿距离,并使用循环来直接枚举该距离对应的边框。我们每次从该正方形边框的上顶点出发,依次经过右顶点、下顶点和左顶点,最后回到上顶点。这样即可完成当前层的遍历。
注意正方形边框中的部分点不一定落在矩阵中,所以我们需要做好边界判断。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution {public : const int dr[4 ] = {1 , 1 , -1 , -1 }; const int dc[4 ] = {1 , -1 , -1 , 1 }; vector <vector <int >> allCellsDistOrder (int R, int C, int r0, int c0) { int maxDist = max(r0, R - 1 - r0) + max(c0, C - 1 - c0); vector <vector <int >> ret; int row = r0, col = c0; ret.push_back({row, col}); for (int dist = 1 ; dist <= maxDist; dist++) { 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) { ret.push_back({row, col}); } row += dr[i]; col += dc[i]; } } } return ret; } };
复杂度分析
时间复杂度:$O\big((R+C)^2\big)$,我们需要遍历矩阵内所有点,同时也会遍历部分超过矩阵部分的点。在最坏情况下,给定的单元格位于矩阵的一个角,例如 $(0,0)$,此时最大的曼哈顿距离为 $R+C-2$,需要遍历的点数为 $2(R+C-2)(R+C-1)+1$,因此时间复杂度为 $O\big((R+C)^2\big)$。
空间复杂度:$O(1)$,不考虑返回值的空间占用。
⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳总 结⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳⏳
总结: 官方题解直接排序自定义sort排序规则遇到好几次了,自己还是不太会,留作以后补充,桶排序方法也比较常见,至于第三种方法说实话没看懂,作为LeetCode官方题解遗留问题,以后回来做补充。
ps:我要赶紧3道题打完卡去学数学了,啊啊啊😮