# 296.Best-Meeting-Point

## 296. Best Meeting Point

## 题目地址

[https://leetcode.com/problems/best-meeting-point/](https://leetcode.com/problems/best-meeting-point/)

## 题目描述

```
A group of two or more people wants to meet and minimize the total travel distance. You are given a 2D grid of values 0 or 1, where each 1 marks the home of someone in the group. The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.

Example:
Input: 

1 - 0 - 0 - 0 - 1
|   |   |   |   |
0 - 0 - 0 - 0 - 0
|   |   |   |   |
0 - 0 - 1 - 0 - 0

Output: 6 

Explanation: Given three people living at (0,0), (0,4), and (2,2):
             The point (0,2) is an ideal meeting point, as the total travel distance 
             of 2+2+2=6 is minimal. So return 6.
```

## 代码

### Approach #1 Sort

`Time: O(mn log mn) && Space: O(mn)` Since there could be at most &#x6D;_×_&#x6E; points, therefore the time complexity is `O(mn log mn)` due to sorting.

As long as there is equal number of points to the left and right of the meeting point, the total distance is minimized.

```java
class Solution {
  public int minTotalDistance(int[][] grid) {
        List<Integer> rows = new ArrayList<>();
      List<Integer> cols = new ArrayList<>();
    for (int row = 0; row < grid.length; row++) {
      for (int col = 0; col < grid[0].length; col++) {
        if (grid[row][col] == 1) {
          rows.add(row);
          cols.add(col);
        }
      }
    }
    int row = rows.get(rows.size() / 2);
    Collections.sort(cols);
    int col = cols.get(cols.size() / 2); // median
    return minDistance1D(rows, row) + minDistance1D(cols, col);
  }

  private int minDistance1D(List<Integer> points, int origin) {
    int distance = 0;
    for (int point : points) {
      distance += Math.abs(point - origin);
    }
    return distance;
  }
}
```

### Approach #2 Collect Coordinates in Sorted Order

`Time: O(mn) && Space: O(mn)`

```java
class Solution {
  public int minTotalDistance(int[][] grid) {
    List<Integer> rows = collectRows(grid);
    List<Integer> cols = collectCols(grid);
    int row = rows.get(rows.size() / 2);
    int col = cols.get(cols.size() / 2);
    return minDistance1D(rows, row) + minDistance1D(cols, col);
  }

  private int minDistance1D(List<Integer> points, int origin) {
    int distance = 0;
    for (int point : points) {
      distance += Math.abs(point - origin);
    }
    return distance;
  }

  private List<Integer> collectRows(int[][] grid) {
    List<Integer> rows = new ArrayList<>();
    for (int row = 0; row < grid.length; row++) {
      for (int col = 0; col < grid[0].length; col++) {
        if (grid[row][col] == 1) {
          rows.add(row);
        }
      }
    }
    return rows;
  }

  private List<Integer> collectCols(int[][] grid) {
    List<Integer> cols = new ArrayList<>();
    for (int col = 0; col < grid[0].length; col++) {
      for (int row = 0; row < grid.length; row++) {
        if (grid[row][col] == 1) {
          cols.add(col);
        }
      }
    }
    return cols;
  }
}
```

### Approach #3 BFS \[Time Limit Exceeded]

```java
class Solution {
  public int minTotalDistance(int[][] grid) {
    int minDistance = Integer.MAX_VALUE;
    for (int row = 0; row < grid.length; row++) {
      for (int col = 0; col < grid[0].length; col++) {
        int distance = search(grid, row, col);
        minDistance = Math.min(distance, minDistance);
      }
    }
    return minDistance;
  }

  private int search(int[][] grid, int row, int col) {
    Queue<Point> q = new LinkedList<>();
    int m = grid.length;
    int n = grid[0].length;
    boolean[][] visited = new boolean[m][n];
    q.add(new Point(row, col, 0));

    int totalDistance = 0;
    while (!q.isEmpty()) {
      Point point = q.poll();
      int r = point.row;
      int c = point.col;
      int d = point.distance;
      if (r < 0 || c < 0 || r >= m || c >= n || visited[r][c]) {
        contineu;
      }
      if (grid[r][c] == 1) {
        totalDistance += d;
      }
      visited[r][c] = true;
      q.add(new Point(r+1, c, d+1));
      q.add(new Point(r-1, c, d+1));
      q.add(new Point(r, c+1, d+1));
      q.add(new Point(r, c-1, d+1));
    }
    return totalDistance;
  }

  public class Point {
    int row;
    int col;
    int distance;
    public Point(int row, int col, int distance) {
      this.row = row;
      this.col = col;
      this.distance = distance;
    }
  }
}
```
