lintcode574- Build Post Office- hard
Posted jasminemzy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lintcode574- Build Post Office- hard相关的知识,希望对你有一定的参考价值。
Given a 2D grid, each cell is either an house 1
or empty 0
(the number zero, one), find the place to build a post office, the distance that post office to all the house sum is smallest. Return the smallest distance. Return -1
if it is not possible.
Notice
- You can pass through house and empty.
- You only build post office on an empty.
Example
Given a grid:
0 1 0 0
1 0 1 1
0 1 0 0
return 6
. (Placing a post office at (1,1), the distance that post office to all the house sum is smallest.)
基本想法:对每个0处计算到所有房子的距离,打擂台选出最近的。遍历每个0肯定是O(n2)了,所以算距离快不快很关键。本题最后用O(1)的方法算距离(如下)。
O(n2)算距离:最粗暴的算法了。二重循环遍历所有1,用manhattan距离计算公式算。
O(n)算距离:一开始先把1的坐标都存进List了,之后直接用manhatten距离计算公式用坐标来算。不过因为每次算要读出所有的1,还是有n的复杂度的。
0(1)算距离:1.O(n2)记录每行房子数和每列房子数 cntRow[], cntCol[] 2.O(n2)记录每行,到其他各行所有房子的距离,的和 distRow[]。 3.O(n2)记录每列,到其他各行所有房子的距离,的和distCol[]。 4.之后对任意一个空地0,比如grid[i][j]就可以O(1)获得到所有房子的距离了:distRow[i] + distCol[j];
其实相当于投资额外的空间,把本来很麻烦的事情拖出来,提前用好几个O(n2)时间的循环算好,存到矩阵里,这样才可能做到以后要拿距离的时候可以直接O(1)调用到。因为本来这道题下限就是O(n2),所以前面那几个预处理用的O(n2)事情不足挂齿。
以后manhattan距离计算优化都可以想到这个,把点与多个点之间的曼哈顿距离和,拆成x上距离和 + y上距离和。 x,y上距离和又拆成 个数 * 行差。
额外贴一个问答看到的思路分析过程。
1.拿到一道题目,就先想想它他的理论下限复杂度是否能达到?然后据此思考解法。
2.这道题目,读入是必须的,而读入的复杂度是rowcolumn,这个就是理论上的最低复杂度了。
能不能达到呢?如果是这样的复杂度,基本就要求我们要把矩阵遍历常数遍就得到结果。
假设我们遍历矩阵的时候,能够O(1)的得到所有的house到这个点距离和,那么就能得到这个理想的复杂度了。这就要求我们能够用不高于rowcolumn的复杂度预处理出所有的house到某一点的距离和。
3.有关于这种在矩阵中求解曼哈顿距离的题目,一般都可以讲 x 与 y 拆分开来解决。
比如我们要所有的house到点(1,1)的距离和,那么可以拆分成求所有的house到第一行的距离和 ansr[1] 与到第一列的距离和 ansc[1],ansr[1]+ansc[1]即为所有的house到点(1,1)的距离和。
根据这个思路,我们只要能预处理出所有的house到某一行的距离和 ansr[] 以及到某一列的距离和 ansc[] ,即可O(1)的得到所有house到某一点的距离和。
4.如何求所有的house到某一行的距离和?
以样例为例:
我们用sr[]来记录每一行有多少个house,于是得到:sr[0]=1,sr[1]=3,sr[2]=1;
所有的house到第 i 行的距离就是:
sum=0;
for j = 0 to 2
sum += abs(i-j)*sr[j];
5.去掉上式中的abs,求所有的house到第i行就变成两个子问题,求所有行号小于 i 的house到第 i 行的距离和+所有行号大于 i 的house到第 i 行的距离和。
对于第一个子问题:我们可以用前缀和来做到O(n)的解决。
用s1[]来记录sr[]的前缀和,即:s1[i]=sr[0]+..sr[i]
然后用s2[]来记录第一个子问题的答案,s2[i]=s2[i-1]+s1[i-1]。
第二个子问题的解法与第一个子问题是相似的,只不过从前缀和变成后缀和而已。
1.O(n2). 最终写法
public class Solution { /* * @param grid: a 2D grid * @return: An integer */ private class Point{ int x; int y; public Point(int x, int y) { this.x = x; this.y = y; } } public int shortestDistance(int[][] grid) { // write your code here if (grid == null || grid.length == 0 || grid[0].length == 0) { return -1; } int h = grid.length; int w = grid[0].length; int[] houseCntRow = new int[h]; int[] houseCntCol = new int[w]; int count = 0; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (grid[i][j] == 1) { count++; houseCntRow[i]++; houseCntCol[j]++; } } } // avoid all being 1 if (count == h * w) { return -1; } int[] distSumRow = new int[h]; int[] distSumCol = new int[w]; for (int row = 0; row < h; row++) { for (int i = 0; i < h; i++) { distSumRow[row] += Math.abs(row - i) * houseCntRow[i]; } } for (int col = 0; col < w; col++) { for (int j = 0; j < w; j++) { distSumCol[col] += Math.abs(col - j) * houseCntCol[j]; } } int minDist = Integer.MAX_VALUE; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (grid[i][j] == 1) { continue; } int dist = distSumRow[i] + distSumCol[j]; minDist = Math.min(minDist, dist); } } return minDist; } }
2.O(n3)时间复杂度的写法 (O(n)算距离):
public class Solution { /* * @param grid: a 2D grid * @return: An integer */ private class Point{ int x; int y; public Point(int x, int y) { this.x = x; this.y = y; } } public int shortestDistance(int[][] grid) { // write your code here if (grid == null || grid.length == 0 || grid[0].length == 0) { return -1; } int h = grid.length; int w = grid[0].length; List<Point> list = new ArrayList<Point>(); int count = 0; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (grid[i][j] == 1) { count++; list.add(new Point(i, j)); } } } if (count == h * w) { return -1; } int minDist = Integer.MAX_VALUE; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (grid[i][j] == 1) { continue; } int dist = 0; for (Point p : list) { dist += Math.abs (i - p.x) + Math.abs(j - p.y); } minDist = Math.min(minDist, dist); } } return minDist; } }
以上是关于lintcode574- Build Post Office- hard的主要内容,如果未能解决你的问题,请参考以下文章
lintcode573- Build Post Office II- hard
Lintcode 573. Build Post Office II 解题报告
lintcode-medium-Segment Tree Build