Reputation: 65
I'm trying to solve a question involving Manhattan distance and matrix.
Question: Given a 2D matrix with where each cell may contain either character '0' or 'x' or 'y'. Find the minimum Manhattan distance between x & y.
Manhattan distance between x & y would be |X(x) - X(y)| + |Y(x) - Y(y)|. X & Y represents row number, column number resp. of cell containing a character in matrix.
Example:
[ x, 0, 0, 0 ]
[ 0, y, 0, y ]
[ x, x, 0, 0 ]
[ 0, y, 0, 0 ]
is given and we've to compute minimum Manhattan distance between x & y; in this case it is 1 (between (3,2) and (4,2)).
A brute force approach would amount to O((m * n)^2) time, how can this be optimised to atleast O(m * n)?
Upvotes: 0
Views: 1631
Reputation: 1433
For each cell of the matrix, the minimum Manhattan distance is just the distance to the nearest x to the left and the nearest y above it, or the nearest x to the left and the nearest y above it. O(n*m)
time to scan the rows and columns and O(n)
memory to track the nearest x and y in each column (compared to an O(n*m)
worst case for a breadth-first search).
def distance(M):
rows = len(M)
cols = len(M[0])
above_x = cols * [-1]
above_y = cols * [-1]
res = float('inf')
for row in range(rows):
left_x = -1
left_y = -1
for col in range(cols):
# track the nearest x and y to the left and above
if M[row][col] == 'x':
above_x[col] = row
left_x = col
if M[row][col] == 'y':
above_y[col] = row
left_y = col
# the shortest distance is just the two distances added together
if left_y > -1 and above_x[col] > -1:
res = min(res, (col - left_y) + (row - above_x[col]))
if left_x > -1 and above_y[col] > -1:
res = min(res, (col - left_x) + (row - above_y[col]))
return res
Upvotes: 0
Reputation: 5703
without use of graph theory
x_i
in set x
y_j
in set y
d(x_i, y_j)
for all ij
if x_s
is size of X
and y_s
size of Y
: runs in O(x_sy_s)
(assuming you know where are x_i
and y_j
beforehand... (O(mn) otherwise)
let {x,y} = `x000,0y0y,xx00,0y00`.replace(/,/g,'').split('').reduce((acc,v,id)=>{
let y = id%4;
let x = (id-y)/4
if(v=='x'||v=='y'){
acc[v].push([x,y]);
}
return acc;
},{x:[],y:[]})
let d = (a,b)=>Math.abs(a[1]-b[1])+Math.abs(a[0]-b[0]);
console.log('dist:', Math.min(...x.map(v=>Math.min(...y.map(w=>d(v,w))))))
Upvotes: 0
Reputation: 2777
Its a classic graph theory problem.
First notice that Manhattan distance is just some shortest path on the grid from one cell to the other.
Then add nodes marked with x
to the queue and do BFS till you visit some y
node and distance to that node will be the answer.
Complexity: O(n*m)
Sample code (C++):
int n = 4;
const int inf = 1234567890;
vector<string>M = {"x000","0y0y","xx00","0y00"};
vector<vector<int>>D(n, vector<int>(n,inf));
queue<array<int,2>>Q;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
if(M[i][j]=='x')
{
Q.push({i,j});
D[i][j]=0;
}
int res = inf;
while(!Q.empty())
{
int row = Q.front()[0];
int col = Q.front()[1];
if(M[row][col]=='y')
{
res=D[row][col];
break;
}
Q.pop();
int dr[] = {-1,1,0,0};
int dc[] = {0,0,-1,1};
for(int k=0; k<4; k++)
{
int r = row + dr[k];
int c = col + dc[k];
if(min(r,c) >=0 && max(r,c) < n && D[r][c]==inf)
{
D[r][c]=D[row][col]+1;
Q.push({r,c});
}
}
}
cout<<res;
Upvotes: 1