296. Best Meeting Point 🔒
Problem Description
You are given an m x n
binary grid where each cell contains either 0 or 1. Each cell with value 1 represents the home of a friend. Your task is to find a meeting point such that the total travel distance for all friends to reach this meeting point is minimized.
The total travel distance is calculated as the sum of individual distances from each friend's home to the meeting point. The distance between any two points is measured using Manhattan Distance, which is defined as distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|
.
For example, if you have a grid with friends at positions (0,0)
, (0,2)
, and (2,1)
, and you choose meeting point (0,1)
, the total travel distance would be:
- Friend at
(0,0)
to(0,1)
:|0-0| + |1-0| = 1
- Friend at
(0,2)
to(0,1)
:|0-0| + |1-2| = 1
- Friend at
(2,1)
to(0,1)
:|0-2| + |1-1| = 2
- Total:
1 + 1 + 2 = 4
The meeting point can be any cell in the grid (not necessarily a cell with value 1). Your goal is to return the minimum possible total travel distance.
Intuition
The key insight is that Manhattan Distance allows us to treat the x and y coordinates independently. Since distance = |x2 - x1| + |y2 - y1|
, we can minimize the sum of x-distances and y-distances separately.
Consider a simpler 1D problem first: if friends live at positions on a line, where should they meet to minimize total travel distance? Let's say friends are at positions [1, 3, 5, 7]
. If we choose the meeting point at position 4
(the median), the total distance is |1-4| + |3-4| + |5-4| + |7-4| = 3 + 1 + 1 + 3 = 8
.
Why does the median work? When we have an even number of points, any position between the two middle points gives the same minimum total distance. When we move the meeting point away from the median, we increase the distance for more friends than we decrease it for others. For instance, if we move from the median towards the left, we get closer to friends on the left but farther from friends on the right - and there are at least as many friends on the right as on the left.
This principle extends to 2D: we can find the median of all row coordinates (treating each friend's row position independently) and the median of all column coordinates. The optimal meeting point is at (median_row, median_column)
.
The beauty of this approach is that we don't need to check every possible cell in the grid. By decomposing the 2D Manhattan Distance problem into two independent 1D problems, we can directly calculate the optimal meeting point as the median position in each dimension.
Solution Approach
The implementation follows the median-finding approach we identified:
-
Extract all friend positions: First, we iterate through the entire grid to find all cells with value 1. For each friend found at position
(i, j)
, we store their row indexi
in arows
list and column indexj
in acols
list. -
Sort the column positions: The
rows
list is naturally sorted since we iterate through the grid row by row. However, thecols
list needs explicit sorting because we collect column indices as we traverse left to right within each row. -
Find the median positions:
- The median row is found at index
len(rows) >> 1
(equivalent tolen(rows) // 2
) - The median column is found at index
len(cols) >> 1
after sorting - For even-length lists, this gives us the upper-middle element, which works as the median for our purpose
- The median row is found at index
-
Calculate total distance: The helper function
f(arr, x)
computes the sum of distances from all points inarr
to positionx
. We apply this function twice:f(rows, i)
: calculates the total vertical distance from all friends to the median rowi
f(cols, j)
: calculates the total horizontal distance from all friends to the median columnj
- The final answer is the sum of these two values
The time complexity is O(m*n + k*log(k))
where k
is the number of friends (cells with value 1), due to the grid traversal and sorting of columns. The space complexity is O(k)
for storing the friend positions.
This solution elegantly leverages the property that Manhattan Distance can be decomposed into independent dimensions, allowing us to solve a 2D optimization problem by solving two simpler 1D median-finding problems.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to illustrate the solution approach.
Consider this 3×3 grid:
1 0 0 0 1 0 1 1 0
Step 1: Extract friend positions We scan the grid and find friends (cells with value 1) at:
- (0, 0) → add row 0 to
rows
, column 0 tocols
- (1, 1) → add row 1 to
rows
, column 1 tocols
- (2, 0) → add row 2 to
rows
, column 0 tocols
- (2, 1) → add row 2 to
rows
, column 1 tocols
After extraction:
rows = [0, 1, 2, 2]
(naturally sorted from our row-by-row traversal)cols = [0, 1, 0, 1]
(unsorted, in order of discovery)
Step 2: Sort column positions
cols
after sorting:[0, 0, 1, 1]
Step 3: Find median positions
- Number of friends: 4
- Median index:
4 >> 1 = 2
(the upper-middle element for even-length lists) - Median row:
rows[2] = 2
- Median column:
cols[2] = 1
- Meeting point:
(2, 1)
Step 4: Calculate total distance
For row distances to median row 2:
|0 - 2| = 2
|1 - 2| = 1
|2 - 2| = 0
|2 - 2| = 0
- Row distance sum:
2 + 1 + 0 + 0 = 3
For column distances to median column 1:
|0 - 1| = 1
|0 - 1| = 1
|1 - 1| = 0
|1 - 1| = 0
- Column distance sum:
1 + 1 + 0 + 0 = 2
Total minimum distance: 3 + 2 = 5
We can verify this is optimal by checking the meeting point (2, 1):
- Friend at (0, 0) travels:
|2-0| + |1-0| = 2 + 1 = 3
- Friend at (1, 1) travels:
|2-1| + |1-1| = 1 + 0 = 1
- Friend at (2, 0) travels:
|2-2| + |1-0| = 0 + 1 = 1
- Friend at (2, 1) travels:
|2-2| + |1-1| = 0 + 0 = 0
- Total:
3 + 1 + 1 + 0 = 5
✓
Notice how the median approach naturally finds the optimal meeting point without checking all possible cells in the grid. The meeting point (2, 1) happens to be where a friend lives, but this isn't always the case - the algorithm would work equally well if the optimal point were an empty cell.
Solution Implementation
1class Solution:
2 def minTotalDistance(self, grid: List[List[int]]) -> int:
3 """
4 Find the minimum total distance for all people to meet at one point.
5 The optimal meeting point is the median of all x-coordinates and y-coordinates.
6
7 Args:
8 grid: 2D grid where 1 represents a person's location, 0 represents empty space
9
10 Returns:
11 Minimum total Manhattan distance for all people to meet
12 """
13
14 def calculate_distance_sum(positions: List[int], meeting_point: int) -> int:
15 """
16 Calculate sum of distances from all positions to the meeting point.
17
18 Args:
19 positions: List of coordinate values (either row or column indices)
20 meeting_point: The target coordinate to measure distance to
21
22 Returns:
23 Sum of absolute distances
24 """
25 return sum(abs(position - meeting_point) for position in positions)
26
27 # Collect all row and column indices where people are located
28 row_indices = []
29 column_indices = []
30
31 for row_index, row in enumerate(grid):
32 for column_index, cell_value in enumerate(row):
33 if cell_value == 1: # Person found at this location
34 row_indices.append(row_index)
35 column_indices.append(column_index)
36
37 # Sort column indices to find median (row indices already sorted due to iteration order)
38 column_indices.sort()
39
40 # Find median positions (optimal meeting point)
41 # Using bit shift for integer division by 2
42 median_row = row_indices[len(row_indices) >> 1]
43 median_column = column_indices[len(column_indices) >> 1]
44
45 # Calculate total distance as sum of row distances and column distances
46 total_distance = calculate_distance_sum(row_indices, median_row) + \
47 calculate_distance_sum(column_indices, median_column)
48
49 return total_distance
50
1class Solution {
2 /**
3 * Finds the minimum total Manhattan distance for all people to meet at one point.
4 * Uses the median property: the optimal meeting point is at the median of all positions.
5 *
6 * @param grid 2D array where 1 represents a person's position, 0 represents empty
7 * @return minimum total Manhattan distance for all people to meet
8 */
9 public int minTotalDistance(int[][] grid) {
10 int rows = grid.length;
11 int cols = grid[0].length;
12
13 // Collect all row indices where people are located
14 List<Integer> rowPositions = new ArrayList<>();
15 // Collect all column indices where people are located
16 List<Integer> colPositions = new ArrayList<>();
17
18 // Traverse the grid to find all people's positions
19 for (int row = 0; row < rows; ++row) {
20 for (int col = 0; col < cols; ++col) {
21 if (grid[row][col] == 1) {
22 // Row positions are already sorted due to traversal order
23 rowPositions.add(row);
24 colPositions.add(col);
25 }
26 }
27 }
28
29 // Sort column positions to find the median
30 // Row positions don't need sorting as they're added in order
31 Collections.sort(colPositions);
32
33 // Find median positions (optimal meeting point)
34 int medianRow = rowPositions.get(rowPositions.size() >> 1); // Equivalent to size / 2
35 int medianCol = colPositions.get(colPositions.size() >> 1);
36
37 // Calculate total distance as sum of distances in each dimension
38 return calculateTotalDistance(rowPositions, medianRow) +
39 calculateTotalDistance(colPositions, medianCol);
40 }
41
42 /**
43 * Calculates the total distance from all points to a target point in one dimension.
44 *
45 * @param positions list of positions in one dimension
46 * @param targetPosition the target meeting position
47 * @return sum of absolute distances from all positions to the target
48 */
49 private int calculateTotalDistance(List<Integer> positions, int targetPosition) {
50 int totalDistance = 0;
51
52 // Sum up the absolute distance from each position to the target
53 for (int position : positions) {
54 totalDistance += Math.abs(position - targetPosition);
55 }
56
57 return totalDistance;
58 }
59}
60
1class Solution {
2public:
3 int minTotalDistance(vector<vector<int>>& grid) {
4 int numRows = grid.size();
5 int numCols = grid[0].size();
6
7 // Store row and column indices of all people (cells with value 1)
8 vector<int> rowIndices;
9 vector<int> colIndices;
10
11 // Collect all row and column positions where people are located
12 for (int row = 0; row < numRows; ++row) {
13 for (int col = 0; col < numCols; ++col) {
14 if (grid[row][col] == 1) {
15 rowIndices.emplace_back(row);
16 colIndices.emplace_back(col);
17 }
18 }
19 }
20
21 // Sort column indices (row indices are already sorted due to iteration order)
22 sort(colIndices.begin(), colIndices.end());
23
24 // Find median positions for both rows and columns
25 // The median minimizes the sum of absolute distances (Manhattan distance)
26 int medianRow = rowIndices[rowIndices.size() / 2];
27 int medianCol = colIndices[colIndices.size() / 2];
28
29 // Lambda function to calculate total distance from all points to a target position
30 auto calculateTotalDistance = [](vector<int>& positions, int targetPosition) {
31 int totalDistance = 0;
32 for (int position : positions) {
33 totalDistance += abs(position - targetPosition);
34 }
35 return totalDistance;
36 };
37
38 // Calculate and return the sum of distances in both dimensions
39 return calculateTotalDistance(rowIndices, medianRow) +
40 calculateTotalDistance(colIndices, medianCol);
41 }
42};
43
1function minTotalDistance(grid: number[][]): number {
2 const numRows: number = grid.length;
3 const numCols: number = grid[0].length;
4
5 // Store row and column indices of all people (cells with value 1)
6 const rowIndices: number[] = [];
7 const colIndices: number[] = [];
8
9 // Collect all row and column positions where people are located
10 for (let row = 0; row < numRows; row++) {
11 for (let col = 0; col < numCols; col++) {
12 if (grid[row][col] === 1) {
13 rowIndices.push(row);
14 colIndices.push(col);
15 }
16 }
17 }
18
19 // Sort column indices (row indices are already sorted due to iteration order)
20 colIndices.sort((a, b) => a - b);
21
22 // Find median positions for both rows and columns
23 // The median minimizes the sum of absolute distances (Manhattan distance)
24 const medianRow: number = rowIndices[Math.floor(rowIndices.length / 2)];
25 const medianCol: number = colIndices[Math.floor(colIndices.length / 2)];
26
27 // Helper function to calculate total distance from all points to a target position
28 const calculateTotalDistance = (positions: number[], targetPosition: number): number => {
29 let totalDistance = 0;
30 for (const position of positions) {
31 totalDistance += Math.abs(position - targetPosition);
32 }
33 return totalDistance;
34 };
35
36 // Calculate and return the sum of distances in both dimensions
37 return calculateTotalDistance(rowIndices, medianRow) +
38 calculateTotalDistance(colIndices, medianCol);
39}
40
Time and Space Complexity
Time Complexity: O(m * n * log(m * n))
The algorithm iterates through the entire grid once to collect positions of all 1
s, which takes O(m * n)
time where m
is the number of rows and n
is the number of columns. The rows
list is already sorted as we traverse row by row, but the cols
list needs to be sorted explicitly using cols.sort()
, which takes O(k * log k)
time where k
is the number of 1
s in the grid. In the worst case, k = m * n
when all cells contain 1
. Finding the median takes O(1)
time, and calculating the total distance using function f
takes O(k)
time for each dimension. Therefore, the overall time complexity is O(m * n + k * log k + k) = O(m * n * log(m * n))
in the worst case.
Space Complexity: O(m * n)
The algorithm uses two lists rows
and cols
to store the coordinates of all 1
s in the grid. In the worst case, when all cells in the grid contain 1
, both lists will have m * n
elements. Therefore, the space complexity is O(k)
where k
is the number of 1
s, which is O(m * n)
in the worst case.
Common Pitfalls
1. Assuming the Meeting Point Must Be at a Friend's Location
A common misconception is thinking the optimal meeting point must be at one of the cells containing a 1 (friend's home). This can lead to inefficient solutions that only check friend locations as potential meeting points.
Why it's wrong: The optimal meeting point can be any cell in the grid, including empty cells (0s). For example, if friends are at positions (0,0) and (0,2), the optimal meeting point is (0,1), which might be an empty cell.
Solution: Use the mathematical property that the median minimizes the sum of absolute deviations. Don't restrict the search to only cells with value 1.
2. Incorrectly Handling the 2D Median Calculation
Some might try to find a "2D median" by treating the problem as finding a single point that minimizes distance in both dimensions simultaneously, leading to complex calculations or incorrect results.
Why it's wrong: Manhattan distance allows us to decompose the problem into two independent 1D problems. The optimal x-coordinate and y-coordinate can be found separately.
Solution: Separate the row and column coordinates into two lists, find the median of each independently, and sum the distances:
# Correct approach - handle dimensions independently
median_row = row_indices[len(row_indices) // 2]
median_column = column_indices[len(column_indices) // 2]
3. Forgetting to Sort the Column Indices
When collecting friend positions by iterating through the grid row by row, the row indices are naturally sorted, but column indices are not. Forgetting to sort the column list before finding the median will give incorrect results.
Why it's wrong: The median requires a sorted list. While row indices are collected in order (0, 0, 1, 1, 2...), column indices might be collected as (0, 2, 1, 3...) depending on friend positions.
Solution: Always sort the column indices before finding the median:
# Row indices are already sorted due to iteration order
# Column indices MUST be sorted
column_indices.sort()
median_column = column_indices[len(column_indices) // 2]
4. Using Mean Instead of Median
Some might intuitively use the average (mean) of all positions instead of the median, thinking it represents the "center" of all friends.
Why it's wrong: The mean minimizes squared distances, not absolute distances. For Manhattan distance (sum of absolute differences), the median is the optimal choice.
Solution: Always use median for minimizing sum of absolute distances:
# Wrong - using mean
mean_row = sum(row_indices) / len(row_indices)
# Correct - using median
median_row = row_indices[len(row_indices) // 2]
What are the two properties the problem needs to have for dynamic programming to be applicable? (Select 2)
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!