296-best-meeting-point
Question
https://leetcode.com/problems/best-meeting-point/description/
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:
given three people living at (0,0), (0,4), and (2,2):
1 - 0 - 0 - 0 - 1
| | | | |
0 - 0 - 0 - 0 - 0
| | | | |
0 - 0 - 1 - 0 - 0
The point (0,2) is an ideal meeting point, as the total travel distance of 2+2+2=6 is minimal. So return 6.
Thought Process
- Brute Force
- Try every point and calculate the 1's distance to this point
- The best distance can be found by using min function
- Time complexity O(m^2n^2)
- Space complexity O(mn)
- Sorting
- The optimal point is at the mean
- For example, 1-1-0-0-1, the optimal point is at x = 1, and assume the total distance is d
- If we move the point to the right, x = 2, the total distance will be d + 2 - 1, since there will be two points on its left and 1 point on its right
- For even number of 1's, we can pick either one of middle as the choice, for example 1-1-0-0-1-1
- Time complexity O(mn + mn log(mn)) = O(mn log(mn))
- Space complexity O(mn)
- Without Sorting
- Write separate function for collecting rows and col
- Time complexity O(mn)
- Space complexity O(mn)
- Two Pointers
- We can modify the distance function to use two pointers, using highIndex - lowIndex
- Time complexity O(mn)
- Space complexity O(mn)
- One pass with Count
- We can modify the distance function to use frequency to find the reach the median
- Time complexity O(mn)
- Space complexity O(mn)
Solution
class Solution {
public int minTotalDistance(int[][] grid) {
if (grid.length == 0 || grid[0].length == 0) return 0;
int min = Integer.MAX_VALUE;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
int dist = calculate(i, j, grid);
min = Math.min(min, dist);
}
}
return min;
}
private int calculate(int m, int n, int[][] grid) {
int dist = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == 1) dist += Math.abs(i - m) + Math.abs(n - j);
}
}
return dist;
}
}
class Solution {
public int minTotalDistance(int[][] grid) {
if (grid.length == 0 || grid[0].length == 0) return 0;
List<Integer> rows = new ArrayList<>();
List<Integer> cols = new ArrayList<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == 1) {
rows.add(i);
cols.add(j);
}
}
}
Collections.sort(cols);
return calDist(rows) + calDist(cols);
}
private int calDist(List<Integer> list) {
int ref = list.get(list.size() / 2);
int dist = 0;
for (int point : list) {
dist += Math.abs(point - ref);
}
return dist;
}
}
class Solution {
public int minTotalDistance(int[][] grid) {
if (grid.length == 0 || grid[0].length == 0) return 0;
List<Integer> rows = collectRow(grid);
List<Integer> cols = collectCol(grid);
return calDist(rows) + calDist(cols);
}
private List<Integer> collectRow(int[][] grid) {
List<Integer> res = new ArrayList<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == 1) {
res.add(i);
}
}
}
return res;
}
private List<Integer> collectCol(int[][] grid) {
List<Integer> res = new ArrayList<>();
for (int i = 0; i < grid[0].length; i++) {
for (int j = 0; j < grid.length; j++) {
if (grid[j][i] == 1) {
res.add(i);
}
}
}
return res;
}
private int calDist(List<Integer> list) {
int ref = list.get(list.size() / 2);
int dist = 0;
for (int point : list) {
dist += Math.abs(point - ref);
}
return dist;
}
}
class Solution {
public int minTotalDistance(int[][] grid) {
if (grid.length == 0 || grid[0].length == 0) return 0;
List<Integer> rows = collectRow(grid);
List<Integer> cols = collectCol(grid);
return calDist(rows) + calDist(cols);
}
private List<Integer> collectRow(int[][] grid) {
List<Integer> res = new ArrayList<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == 1) {
res.add(i);
}
}
}
return res;
}
private List<Integer> collectCol(int[][] grid) {
List<Integer> res = new ArrayList<>();
for (int i = 0; i < grid[0].length; i++) {
for (int j = 0; j < grid.length; j++) {
if (grid[j][i] == 1) {
res.add(i);
}
}
}
return res;
}
private int calDist(List<Integer> list) {
int i = 0, j = list.size() - 1;
int dist = 0;
while (i < j) {
dist += list.get(j) - list.get(i);
i++;
j--;
}
return dist;
}
}
class Solution {
public int minTotalDistance(int[][] grid) {
if (grid.length == 0 || grid[0].length == 0) return 0;
int[] rowCount = new int[grid.length];
int[] colCount = new int[grid[0].length];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == 1) {
rowCount[i]++;
colCount[j]++;
}
}
}
return calDist(rowCount) + calDist(colCount);
}
private int calDist(int[] count) {
int i = 0, j = count.length - 1;
int dist = 0;
while (i < j) {
int k = Math.min(count[i], count[j]);
dist += k * (j - i);
count[i] -= k;
count[j] -= k;
if (count[i] == 0) i++;
if (count[j] == 0) j--;
}
return dist;
}
}