- 思路:
- 1.要求最小,那么人越多走的步数总和肯定是越大的
- 2.所以应该找人少的那一行开始出发(题中人是用1表示)
- 3.先计算出每一行分别有多少个1,计算出每一列分别有多少个1
- 4.先进行首尾两行1个数的比较,哪一行少就往中间缩进,最终会缩成一行
- 5.然后左右两列1个数的比较,哪一列少就往中间缩进,最终会缩到一个点上
- 6.这个点就是最近的距离和的点, 在每一步缩进的时候累计步数,既可以得到最短距离和啦
- 7.总结,先是上下压缩,再是左右压缩,最终压缩到一个点.这个点就是最佳点
给你一个 m x n 的二进制网格 grid ,其中 1 表示某个朋友的家所处的位置。返回 最小的 总行走距离 。
总行走距离 是朋友们家到碰头地点的距离之和。
我们将使用 曼哈顿距离 来计算,其中 distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y| 。
来源:力扣(LeetCode) 链接:leetcode.cn/problems/be… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public int minTotalDistance(int[][] grid) {
int N = grid.length; // 行
int M = grid[0].length; // 列
int[] iOnes = new int[N]; // 统计每一行有多少个1
int[] jOnes = new int[M]; // 统计每一列有多少个1
for(int i = 0; i < N;i++) {
for(int j = 0; j< M; j++) {
if(grid[i][j] == 1) {
iOnes[i]++;
jOnes[j]++;
}
}
}
//统计工作完毕
//----------------------------------------
//首行和尾行比较,谁小谁往中间累加缩进
int total = 0;
int up = 0; // 首行
int down = N - 1; // 尾行
int upRest = 0; // 上往下缩之前行的1个数总和
int downRest = 0; // 下往上缩之前行的1个数总和
while(up < down) {
if(iOnes[up] + upRest <= iOnes[down] + downRest) {
total += iOnes[up] + upRest;
upRest += iOnes[up++];
}else {
total += iOnes[down] + downRest;
downRest += iOnes[down--];
}
}
//----------------------------------------
//首列和尾列比较,谁小谁往中间累加缩进
int left = 0; // 首列
int right = M - 1; // 尾列
int leftRest = 0; // 左往右缩进之前的1个数总和
int rightRest = 0; // 右往左锁进之前的1个数总和
while(left < right) {
if(jOnes[left] + leftRest <= jOnes[right] + rightRest) {
total += jOnes[left] + leftRest;
leftRest += jOnes[left++];
}else {
total += jOnes[right] + rightRest;
rightRest += jOnes[right--];
}
}
//-------------------结果
return total;
}
}