专栏 | 九章算法
网址 | www.jiuzhang.com

1.题目描述
给你一个二维网格,每个格子是房子 1 或者空地 0。找到一个空地修建一个办公室,使得这个办公室到所有的房子的距离之和最小。 返回最小的距离和。如果无法修建,那么返回 -1.
样例:

返回6。
2.算法分析
- 因为这个题目要求无解的时候返回 -1 ,那么我们就先想一下无解的情况。
(1)网格不存在,即行数为0或者列数为0; (2)网格存在,但是没有地方修,也就是没有空地。
之后就要开始要想如何解决这个问题了。
- 题目是要求所有的房子到某一空地的最小曼哈顿距离和,那我们就有一个朴素的想法,直接枚举所有的空地,求出所有的房子到该空地的曼哈顿距离和,从这些距离和中选取最小的一个即可。
(ps:曼哈顿距离:dis=|x2-x1|+|y2-y1|)
伪代码:

接下来就是改进这个朴素的做法。
- 观察上述伪代码,显然求所有的房子到某一点的曼哈顿距离和是可以通过预处理实现O(1)询问的。
这里就要先提到有关曼哈顿距离的一个常用技巧了:将曼哈顿距离拆分成 X 轴距离与 Y 轴距离。
设两个点:(x1,y1)、(x2,y2) 曼哈顿距离:dis=|x2-x1|+|y2-y1|
根据上面这个式子,我们就可以把求两个点的曼哈顿距离拆分成求两个点在 X 轴上的距离与求两个点在 Y 轴上的距离。
有了这个拆分,就有了预处理的基础。
- 我们现在以对 X 轴距离做预处理为例进行讲解。
我们先预处理出一个rowSum数组,rowSum[i]记录第 i 行一共有几个房子。
那么对于一个点(i,j),从第 0 。。。i 行的所有房子到该点的 X 轴距离和即等同于从第0。。。i 行的所有房子到第 i 行的 X 轴距离和。
用prefixSum1[i]表示从第0。。。i 行的所有房子到第 i 行的一共有多少房子; 用prefixSum2[i]表示从第0。。。i 行的所有房子到第 i 行的X 轴距离和,即得到下式:

根据推导的式子,prefixsum1与prefixsum2都可以通过O(row)的预处理得到。
这样我们就得到了从第0。。。i 行的所有房子到第 i 行的 X 轴距离和。
同理,还可以通过 O(row) 的预处理得到从第 i 。。。n - 1 行的所有房子到第 i 行的 X 轴距离和。
将以上的两个预处理的值相加,即可得到:所有的房子到第 i 行的距离和,将其记为ansRow[i]。
综上,我们就可以通过O(row)的预处理得到所有房子到某一 行的距离和,并记录在ansRow[] 数组里。
- 通过与第四点相同的思路,我们可以通过一个O(column)的预处理得到所有房子到某一列的距离和,并记录在ansColumn[] 数组里。
于是,所有房子到某一点(i,j)的曼哈顿距离和即为:ansRow[i] + ansColumn[j]。 代码的总体复杂度就下降到了O(row*column)。
3.参考代码

4.面试官角度分析
如果这道题能够用bfs方法写出来可以达到hire的程度。如果能够优化,想到预处理的方法那么就可以拿到strong hire.
5.LintCode 相关问题
推荐阅读
- 12 个 tips 教你搞定 onsite!
- 25 个 questions, 教你向面试官提问!
- 10 个 tips 教你搞定电面!
- 北美IT企业fulltime薪资大曝光
- IT 简历模板大放送 | 《如何写好技术简历》讲座精华总结
- 面试遇到做过的题怎么办?
- 冷冻期大揭秘 | Google、FB、Amazon、Linkedin冷冻期
- 面试前如何了解一家IT企业?试试官方技术博客!
- Google晋升机制 | 大公司如何升级打怪, 获得晋升?
欢迎关注我的微信公众号:九章算法(ninechapter)。
精英程序员交流社区,定期发布面试题、面试技巧、求职信息等
