Given n non-negative integers a1, a2, ..., an, where each represents a
point at coordinate (i, ai). n vertical lines are drawn such that the
two endpoints of line i is at (i, ai) and (i, 0). Find two lines,
which together with x-axis forms a container, such that the container
contains the most water.
Note: You may not slant the container.
One solution could be that we take each and every line and find area with every line. This takes O(n^2). Not time efficient.
Another solution could be using DP to find the maximum area for every index, and then at index n, we will get the maximum area.
I think it's O(n).
Could there be more better solutions?
int maxArea(vector<int> &height) {
int ret = 0;
int left = 0, right = height.size() - 1;
while (left < right) {
ret = max(ret, (right - left) * min(height[left], height[right]));
if (height[left] <= height[right])
left++;
else
right--;
}
return ret;
}
Many people here are mistaking this problem to maximal rectangle problem, which is not the case.
Solution
Delete all the elements aj such that ai >= aj =< ak and i > j < k. This can be done in linear time.
Find the maximum value am
Let as = a1
For j = 2 through m-1, if as >= aj, delete aj, else as = aj
Let as = an
For j = n-1 through m+1, if as >= aj, delete aj, else as = aj
Notice that the resulting values look like a pyramid, that is, all the elements on the left of the maximum are strictly increasing and on the right are strictly decreasing.
i=1, j=n. m is location of max.
While i<=m and j>=m
Find area between ai and aj and keep track of the max
If ai < aj, i+=1, else j-=1
Complexity is linear (O(n))
Here is an implementation with Java:
Basic idea is to use two pointers from front and back, and calculate the area along the way.
public int maxArea(int[] height) {
int i = 0, j = height.length-1;
int max = Integer.MIN_VALUE;
while(i < j){
int area = (j-i) * Math.min(height[i], height[j]);
max = Math.max(max, area);
if(height[i] < height[j]){
i++;
}else{
j--;
}
}
return max;
}
Here is a clean Python3 solution. The runtime for this solution is O(n). It is important to remember that the area formed between two lines is determined by the height of the shorter line and the distance between the lines.
def maxArea(height):
"""
:type height: List[int]
:rtype: int
"""
left = 0
right = len(height) - 1
max_area = 0
while (left < right):
temp_area = ((right - left) * min(height[left], height[right]))
if (temp_area > max_area):
max_area = temp_area
elif (height[right] > height[left]):
left = left + 1
else:
right = right - 1
return max_area
This problem can be solved in linear time.
Construct a list of possible left walls (position+height pairs), in order from highest to lowest. This is done by taking the leftmost possible wall and adding it to the list, then going through all possible walls, from left to right, and taking every wall that is larger than the last wall added to the list. For example, for the array
2 5 4 7 3 6 2 1 3
your possible left walls would be (pairs are (pos, val)):
(3, 7) (1, 5) (0, 2)
Construct a list of possible right walls in the same way, but going from right to left. For the above array the possible right walls would be:
(3, 7) (5, 6) (8, 3)
Start your water level as high as possible, that is the minimum of heights of the walls at the front of the two lists. Calculate the total volume of water using those walls (it might be negative or zero, but that is ok), then drop the water level by popping an element off of one of the lists such that the water level drops the least. Calculate the possible water volume at each of these heights and take the max.
Running this algorithm on these lists would look like this:
L: (3, 7) (1, 5) (0, 2) # if we pop this one then our water level drops to 5
R: (3, 7) (5, 6) (8, 3) # so we pop this one since it will only drop to 6
Height = 7
Volume = (3 - 3) * 7 = 0
Max = 0
L: (3, 7) (1, 5) (0, 2) # we pop this one now so our water level drops to 5
R: (5, 6) (8, 3) # instead of 3, like if we popped this one
Height = 6
Volume = (5 - 3) * 6 = 12
Max = 12
L: (1, 5) (0, 2)
R: (5, 6) (8, 3)
Height = 5
Volume = (5 - 1) * 5 = 20
Max = 20
L: (1, 5) (0, 2)
R: (8, 3)
Height = 3
Volume = (8 - 1) * 3 = 21
Max = 21
L: (0, 2)
R: (8, 3)
Height = 2
Volume = (8 - 0) * 2 = 16
Max = 21
Steps 1, 2, and 3 all run in linear time, so the complete solution also takes linear time.
The best answer is by Black_Rider, however they did not provide an explanation.
I've found a very clear explanation on this blog. Shortly, it goes as follows:
Given array height of length n:
Start with the widest container you can, i.e. from left side at 0 to right side at n-1.
If a better container exists it will be narrower, so its both sides must be higher than the lower of currently chosen sides.
So, change left to (left+1) if height[left] < height[right], otherwise change right to (right-1).
Calculate new area, if it's better than what you have so far, replace.
If left < right, start over from 2.
My implementation in C++:
int maxArea(vector<int>& height) {
auto current = make_pair(0, height.size() - 1);
auto bestArea = area(height, current);
while (current.first < current.second) {
current = height[current.first] < height[current.second]
? make_pair(current.first + 1, current.second)
: make_pair(current.first, current.second - 1);
auto nextArea = area(height, current);
bestArea = max(bestArea, nextArea);
}
return bestArea;
}
inline int area(const vector<int>& height, const pair<int, int>& p) {
return (p.second - p.first) * min(height[p.first], height[p.second]);
}
This problem is a simpler version of The Maximal Rectangle Problem. The given situation can be view as a binary matrix. Consider the rows of the matrix as X-axis and columns as Y-axis. For every element a[i] in the array, set
Matrix[i][0] = Matrix[i][1] = ..... = Matrix[i][a[i]] = 1
For e.g - For a[] = { 5, 3, 7, 1}, our binary matrix is given by:
1111100
1110000
1111111
1000000
Related
Consider this cartesian graph where each index represents a weight.
[3, 2, 1, 4, 2
1, 3, 3, 2, 2
S, 3, 4, 1, D
3, 1, 2, 4, 3
4, 2, 3, 1, 4]
A man is standing at source 'S' and he has to reach destination 'D' at minimum cost. Constraints are:
If the man moves from one index to another index where both index share same cost, the cost of moving man is '1'.
If the man moves from one index to another index where both indexes have different cost, the cost of moving man is abs(n-m)*10 + 1.
Last but not the least, man can only move up, down, left & right. No diagonal moves.
Which data structure & algorithm is best suited for this problem. I have thought of representing this problem as a graph and use one of the greedy approaches but could not reach to clean solution in my mind.
I would use A* to solve the problem. The distance can be estimated by dx + dy + 10 * dValue + distance travelled (it is impossible that the way is shorter than that, see example at the bottom). The idea of A* is to expand always the node with the lowest estimated distance, as soon as you find the destination node you are finished. This works if the estimation never over-estimates the distance. Here is an implementation in JS (fiddle):
function solve(matrix, sRow, sCol, eRow, eCol) {
if (sRow == eRow && sCol == eCol)
return 0;
let n = matrix.length, m = matrix[0].length;
let d = [], dirs = [[-1, 0], [0, 1], [1, 0], [0, -1]];
for (let i = 0; i < n; i++) {
d.push([]);
for (let j = 0; j < m; j++)
d[i].push(1000000000);
}
let list = [[sRow, sCol, 0]];
d[sRow][sCol] = 0;
for (;;) {
let pos = list.pop();
for (let i = 0; i < dirs.length; i++) {
let r = pos[0] + dirs[i][0], c = pos[1] + dirs[i][1];
if (r >= 0 && r < n && c >= 0 && c < m) {
let v = d[pos[0]][pos[1]] + 1 + 10 * Math.abs(matrix[pos[0]][pos[1]] - matrix[r][c]);
if (r == eRow && c == eCol)
return v;
if (v < d[r][c]) {
d[r][c] = v;
list.push([r, c, v + Math.abs(r - eRow) + Math.abs(c - eCol) + 10 * Math.abs(matrix[r][c] - matrix[eRow][eCol])]);
}
}
}
list.sort(function(a, b) {
if (a[2] > b[2])
return -1;
if (a[2] < b[2])
return 1;
return 0;
});
}
}
The answer for the example is 46 and only 8 nodes are getting expanded!
Estimation example, from (0,0) to D:
distance from S to (0,0) is 22
dx = abs(0 - 4) = 4
dy = abs(0 - 2) = 2
dValue = abs(3 - 1) = 2
estimation = distance + dx + dy + 10 * dValue = 22 + 4 + 2 + 10 * 2 = 48
Note: the implementation uses rows and columns insted of x and y, so they are swapped, it doesn't really matter it just has to be consistent.
Although not explicitly stated, in the problem formulation there seem to be only positive node weights, which means that a shortest path will have no repetition of nodes. As the cost does not depend on the nodes only, approaches like the Bellman-Ford algorithm or the algorithm by Dijkstra are not suitable.
That being said, apparently the path can be found recursively by using depth-first search, where nodes which are currently occuring in the stack may not be visited. Every time the destination is reached, the current path (which is contained in the stack at each time the destination is reached) along with its associated cost, which could be maintained in an auxiliary variable, could be evaluated against the best previously found path. On termination, a path with minimum cost would be stored.
Given the matrix A x A and a number of movements N.
And walking like a spiral:
right while possible, then
down while possible, then
left while possible, then
up while possible, repeat until got N.
Image with example (A = 8; N = 36)
In this example case, the final square is (4; 7).
My question is: Is it possible to use a generic formula to solve this?
Yes, it is possible to calculate the answer.
To do so, it will help to split up the problem into three parts.
(Note: I start counting at zero to simplify the math. This means that you'll have to add 1 to some parts of the answer. For instance, my answer to A = 8, N = 36 would be the final square (3; 6), which has the label 35.)
(Another note: this answer is quite similar to Nyavro's answer, except that I avoid the recursion here.)
In the first part, you calculate the labels on the diagonal:
(0; 0) has label 0.
(1; 1) has label 4*(A-1). The cycle can be evenly split into four parts (with your labels: 1..7, 8..14, 15..21, 22..27).
(2; 2) has label 4*(A-1) + 4*(A-3). After taking one cycle around the A x A matrix, your next cycle will be around a (A - 2) x (A - 2) matrix.
And so on. There are plenty of ways to now figure out the general rule for (K; K) (when 0 < K < A/2). I'll just pick the one that's easiest to show:
4*(A-1) + 4*(A-3) + 4*(A-5) + ... + 4*(A-(2*K-1)) =
4*A*K - 4*(1 + 3 + 5 + ... + (2*K-1)) =
4*A*K - 4*(K + (0 + 2 + 4 + ... + (2*K-2))) =
4*A*K - 4*(K + 2*(0 + 1 + 2 + ... + (K-1))) =
4*A*K - 4*(K + 2*(K*(K-1)/2)) =
4*A*K - 4*(K + K*(K-1)) =
4*A*K - 4*(K + K*K - K) =
4*A*K - 4*K*K =
4*(A-K)*K
(Note: check that 4*(A-K)*K = 28 when A = 8 and K = 1. Compare this to the label at (2; 2) in your example.)
Now that we know what labels are on the diagonal, we can figure out how many layers (say K) we have to remove from our A x A matrix so that the final square is on the edge. If we do this, then answering our question
What are the coordinates (X; Y) when I take N steps in a A x A matrix?
can be done by calculating this K and instead solve the question
What are the coordinates (X - K; Y - K) when I take N - 4*(A-K)*K steps in a (A - 2*K) x (A - 2*K) matrix?
To do this, we should find the largest integer K such that K < A/2 and 4*(A-K)*K <= N.
The solution to this is K = floor(A/2 - sqrt(A*A-N)/2).
All that remains is to find out the coordinates of a square that is N along the edge of some A x A matrix:
if 0*E <= N < 1*E, the coordinates are (0; N);
if 1*E <= N < 2*E, the coordinates are (N - E; E);
if 2*E <= N < 3*E, the coordinates are (E; 3*E - N); and
if 3*E <= N < 4*E, the coordinates are (4*E - N; 0).
Here, E = A - 1.
To conclude, here is a naive (layerNumber gives incorrect answers for large values of a due to float inaccuracy) Haskell implementation of this answer:
finalSquare :: Integer -> Integer -> Maybe (Integer, Integer)
finalSquare a n
| Just (x', y') <- edgeSquare a' n' = Just (x' + k, y' + k)
| otherwise = Nothing
where
k = layerNumber a n
a' = a - 2*k
n' = n - 4*(a-k)*k
edgeSquare :: Integer -> Integer -> Maybe (Integer, Integer)
edgeSquare a n
| n < 1*e = Just (0, n)
| n < 2*e = Just (n - e, e)
| n < 3*e = Just (e, 3*e - n)
| n < 4*e = Just (4*e - n, 0)
| otherwise = Nothing
where
e = a - 1
layerNumber :: Integer -> Integer -> Integer
layerNumber a n = floor $ aa/2 - sqrt(aa*aa-nn)/2
where
aa = fromInteger a
nn = fromInteger n
Here is the possible solution:
f a n | n < (a-1)*1 = (0, n)
| n < (a-1)*2 = (n-(a-1), a-1)
| n < (a-1)*3 = (a-1, 3*(a-1)-n)
| n < (a-1)*4 = (4*(a-1)-n, 0)
| otherwise = add (1,1) (f (a-2) (n - 4*(a-1))) where
add (x1, y1) (x2, y2) = (x1+x2, y1+y2)
This is a basic solution, it may be generalized further - I just don't know how much generalization you need. So you can get the idea.
Edit
Notes:
The solution is for 0-based index
Some check for existence is required (n >= a*a)
I'm going to propose a relatively simple workaround here which generates all the indices in O(A^2) time so that they can later be accessed in O(1) for any N. If A changes, however, we would have to execute the algorithm again, which would once more consume O(A^2) time.
I suggest you use a structure like this to store the indices to access your matrix:
Coordinate[] indices = new Coordinate[A*A]
Where Coordinate is just a pair of int.
You can then fill your indices array by using some loops:
(This implementation uses 1-based array access. Correct expressions containing i, sentinel and currentDirection accordingly if this is an issue.)
Coordinate[] directions = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };
Coordinate c = new Coordinate(1, 1);
int currentDirection = 1;
int i = 1;
int sentinel = A;
int sentinelIncrement = A - 1;
boolean sentinelToggle = false;
while(i <= A * A) {
indices[i] = c;
if (i >= sentinel) {
if (sentinelToggle) {
sentinelIncrement -= 1;
}
sentinel += sentinelIncrement;
sentinelToggle = !sentinelToggle;
currentDirection = currentDirection mod 4 + 1;
}
c += directions[currentDirection];
i++;
}
Alright, off to the explanation: I'm using a variable called sentinel to keep track of where I need to switch directions (directions are simply switched by cycling through the array directions).
The value of sentinel is incremented in such a way that it always has the index of a corner in our spiral. In your example the sentinel would take on the values 8, 15, 22, 28, 34, 39... and so on.
Note that the index of "sentinel" increases twice by 7 (8, 15 = 8 + 7, 22 = 15 + 7), then by 6 (28 = 22 + 6, 34 = 28 + 6), then by 5 and so on. In my while loop I used the boolean sentinelToggle for this. Each time we hit a corner of the spiral (this is exactly iff i == sentinel, which is where the if-condition comes in) we increment the sentinel by sentinelIncrement and change the direction we're heading. If sentinel has been incremented twice by the same value, the if-condition if (sentinelToggle) will be true, so sentinelIncrement is decreased by one. We have to decrease sentinelIncrement because our spiral gets smaller as we go on.
This goes on as long as i <= A*A, that is, as long as our array indices has still entries that are zero.
Note that this does not give you a closed formula for a spiral coordinate in respect to N (which would be O(1) ); instead it generates the indices for all N which takes up O(A^2) time and after that guarantees access in O(1) by simply calling indices[N].
O(n^2) hopefully shouldn't hurt too badly because I'm assuming that you'll also need to fill your matrix at some point which also takes O(n^2).
If efficiency is a problem, consider getting rid off sentinelToggle so it doesn't mess up branch prediction. Instead, decrement sentinelIncrement every time the while condition is met. To get the same effect for your sentinel value, simply start sentinelIncrement at (A - 1) * 2 and every time the if-condition is met, execute:
sentinel += sentinelIncrement / 2
The integer division will have the same effect as only decreasing sentinelIncrement every second time. I didn't do this whole thing in my version because I think it might be more easily understandable with just a boolean value.
Hope this helps!
Say you have a vertical game board of length n (being the number of spaces). And you have a three-sided die that has the options: go forward one, stay and go back one. If you go below or above the number of board game spaces it is an invalid game. The only valid move once you reach the end of the board is "stay". Given an exact number of die rolls t, is it possible to algorithmically work out the number of unique dice rolls that result in a winning game?
So far I've tried producing a list of every possible combination of (-1,0,1) for the given number of die rolls and sorting through the list to see if any add up to the length of the board and also meet all the requirements for being a valid game. But this is impractical for dice rolls above 20.
For example:
t=1, n=2; Output=1
t=3, n=2; Output=3
You can use a dynamic programming approach. The sketch of a recurrence is:
M(0, 1) = 1
M(t, n) = T(t-1, n-1) + T(t-1, n) + T(t-1, n+1)
Of course you have to consider the border cases (like going off the board or not allowing to exit the end of the board, but it's easy to code that).
Here's some Python code:
def solve(N, T):
M, M2 = [0]*N, [0]*N
M[0] = 1
for i in xrange(T):
M, M2 = M2, M
for j in xrange(N):
M[j] = (j>0 and M2[j-1]) + M2[j] + (j+1<N-1 and M2[j+1])
return M[N-1]
print solve(3, 2) #1
print solve(2, 1) #1
print solve(2, 3) #3
print solve(5, 20) #19535230
Bonus: fancy "one-liner" with list compreehension and reduce
def solve(N, T):
return reduce(
lambda M, _: [(j>0 and M[j-1]) + M[j] + (j<N-2 and M[j+1]) for j in xrange(N)],
xrange(T), [1]+[0]*N)[-1]
Let M[i, j] be an N by N matrix with M[i, j] = 1 if |i-j| <= 1 and 0 otherwise (and the special case for the "stay" rule of M[N, N-1] = 0)
This matrix counts paths of length 1 from position i to position j.
To find paths of length t, simply raise M to the t'th power. This can be performed efficiently by linear algebra packages.
The solution can be read off: M^t[1, N].
For example, computing paths of length 20 on a board of size 5 in an interactive Python session:
>>> import numpy
>>> M = numpy.matrix('1 1 0 0 0;1 1 1 0 0; 0 1 1 1 0; 0 0 1 1 1; 0 0 0 0 1')
>>> M
matrix([[1, 1, 0, 0, 0],
[1, 1, 1, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 1, 1, 1],
[0, 0, 0, 0, 1]])
>>> M ** 20
matrix([[31628466, 51170460, 51163695, 31617520, 19535230],
[51170460, 82792161, 82787980, 51163695, 31617520],
[51163695, 82787980, 82792161, 51170460, 31628465],
[31617520, 51163695, 51170460, 31628466, 19552940],
[ 0, 0, 0, 0, 1]])
So there's M^20[1, 5], or 19535230 paths of length 20 from start to finish on a board of size 5.
Try a backtracking algorithm. Recursively "dive down" into depth t and only continue with dice values that could still result in a valid state. Propably by passing a "remaining budget" around.
For example, n=10, t=20, when you reached depth 10 of 20 and your budget is still 10 (= steps forward and backwards seemed to cancelled), the next recursion steps until depth t would discontinue the 0 and -1 possibilities, because they could not result in a valid state at the end.
A backtracking algorithms for this case is still very heavy (exponential), but better than first blowing up a bubble with all possibilities and then filtering.
Since zeros can be added anywhere, we'll multiply those possibilities by the different arrangements of (-1)'s:
X (space 1) X (space 2) X (space 3) X (space 4) X
(-1)'s can only appear in spaces 1,2 or 3, not in space 4. I got help with the mathematical recurrence that counts the number of ways to place minus ones without skipping backwards.
JavaScript code:
function C(n,k){if(k==0||n==k)return 1;var p=n;for(var i=2;i<=k;i++)p*=(n+1-i)/i;return p}
function sumCoefficients(arr,cs){
var s = 0, i = -1;
while (arr[++i]){
s += cs[i] * arr[i];
}
return s;
}
function f(n,t){
var numMinusOnes = (t - (n-1)) >> 1
result = C(t,n-1),
numPlaces = n - 2,
cs = [];
for (var i=1; numPlaces-i>=i-1; i++){
cs.push(-Math.pow(-1,i) * C(numPlaces + 1 - i,i));
}
var As = new Array(cs.length),
An;
As[0] = 1;
for (var m=1; m<=numMinusOnes; m++){
var zeros = t - (n-1) - 2*m;
An = sumCoefficients(As,cs);
As.unshift(An);
As.pop();
result += An * C(zeros + 2*m + n-1,zeros);
}
return result;
}
Output:
console.log(f(5,20))
19535230
You are situated in an grid at position x,y. The dimensions of the row is dx,dy. In one step, you can walk one step ahead or behind in the row or the column. In how many ways can you take M steps such that you do not leave the grid at any point ?You can visit the same position more than once.
You leave the grid if you for any x,y either x,y <= 0 or x,y > dx,dy.
1 <= M <= 300
1 <= x,y <= dx,dy <= 100
Input:
M
x y
dx dy
Output:
no of ways
Example:
Input:
1
6 6
12 12
Output:
4
Example:
Input:
2
6 6
12 12
Output:
16
If you are at position 6,6 then you can walk to (6,5),(6,7),(5,6),(7,6).
I am stuck at how to use Pascal's Triangle to solve it.Is that the correct approach? I have already tried brute force but its too slow.
C[i][j], Pascal Triangle
C[i][j] = C[i - 1][j - 1] + C[i - 1][j]
T[startpos][stp]
T[pos][stp] = T[pos + 1][stp - 1] + T[pos - 1][stp - 1]
You can solve 1d problem with the formula you provided.
Let H[pos][step] be number of ways to move horizontal using given number of steps.
And V[pos][step] be number of ways to move vertical sing given number of steps.
You can iterate number of steps that will be made horizontal i = 0..M
Number of ways to move so is H[x][i]*V[y][M-i]*C[M][i], where C is binomial coefficient.
You can build H and V in O(max(dx,dy)*M) and do second step in O(M).
EDIT: Clarification on H and V. Supppose that you have line, that have d cells: 1,2,...,d. You're standing at cell number pos then T[pos][step] = T[pos-1][step-1] + T[pos+1][step-1], as you can move either forward or backward.
Base cases are T[0][step] = 0, T[d+1][step] = 0, T[pos][0] = 1.
We build H assuming d = dx and V assuming d = dy.
EDIT 2: Basically, the idea of algorithm is since we move in one of 2 dimensions and check is also based on each dimension independently, we can split 2d problem in 2 1d problems.
One way would be an O(n^3) dynamic programming solution:
Prepare a 3D array:
int Z[dx][dy][M]
Where Z[i][j][n] holds the number of paths that start from position (i,j) and last n moves.
The base case is Z[i][j][0] = 1 for all i, j
The recursive case is Z[i][j][n+1] = Z[i-1][j][n] + Z[i+1][j][n] + Z[i][j-1][n] + Z[i][j+1][n] (only include terms in the sumation that are on the map)
Once the array is filled out return Z[x][y][M]
To save space you can discard each 2D array for n after it is used.
Here's a Java solution I've built for the original hackerrank problem. For big grids runs forever. Probably some smart math is needed.
long compute(int N, int M, int[] positions, int[] dimensions) {
if (M == 0) {
return 1;
}
long sum = 0;
for (int i = 0; i < N; i++) {
if (positions[i] < dimensions[i]) {
positions[i]++;
sum += compute(N, M - 1, positions, dimensions);
positions[i]--;
}
if (positions[i] > 1) {
positions[i]--;
sum += compute(N, M - 1, positions, dimensions);
positions[i]++;
}
}
return sum % 1000000007;
}
There is a matrix, m×n. Several groups of people locate at some certain spots. In the following example, there are three groups and the number 4 indicates there are four people in this group. Now we want to find a meeting point in the matrix so that the cost of all groups moving to that point is the minimum. As for how to compute the cost of moving one group to another point, please see the following example.
Group1: (0, 1), 4
Group2: (1, 3), 3
Group3: (2, 0), 5
. 4 . .
. . . 3
5 . . .
If all of these three groups moving to (1, 1), the cost is:
4*((1-0)+(1-1)) + 5*((2-1)+(1-0))+3*((1-1)+(3-1))
My idea is :
Firstly, this two dimensional problem can be reduced to two one dimensional problem.
In the one dimensional problem, I can prove that the best spot must be one of these groups.
In this way, I can give a O(G^2) algorithm.(G is the number of group).
Use iterator's example for illustration:
{(-100,0,100),(100,0,100),(0,1,1)},(x,y,population)
for x, {(-100,100),(100,100),(0,1)}, 0 is the best.
for y, {(0,100),(0,100),(1,1)}, 0 is the best.
So it's (0, 0)
Is there any better solution for this problem.
I like the idea of noticing that the objective function can be decomposed to give the sum of two one-dimensional problems. The remaining problems look a lot like the weighted median to me (note "solves the following optimization problem in "http://www.stat.ucl.ac.be/ISdidactique/Rhelp/library/R.basic/html/weighted.median.html" or consider what happens to the objective function as you move away from the weighted median).
The URL above seems to say the weighted median takes time n log n, which I guess means that you could attain their claim by sorting the data and then doing a linear pass to work out the weighted median. The numbers you have to sort are in the range [0, m] and [0, n] so you could in theory do better if m and n are small, or - of course - if you are given the data pre-sorted.
Come to think of it, I don't see why you shouldn't be able to find the weighted median with a linear time randomized algorithm similar to that used to find the median (http://en.wikibooks.org/wiki/Algorithms/Randomization#find-median) - repeatedly pick a random element, use it to partition the items remaining, and work out which half the weighted median should be in. That gives you expected linear time.
I think this can be solved in O(n>m?n:m) time and O(n>m?n:m) space.
We have to find the median of x coordinates and median of all y coordinates in the k points and the answer will be (x_median,y_median);
Assumption is this function takes in the following inputs:
total number of points :int k= 4+3+5 = 12;
An array of coordinates:
struct coord_t c[12] = {(0,1),(0,1),(0,1), (0,1), (1,3), (1,3),(1,3),(2,0),(2,0),(2,0),(2,0),(2,0)};
c.int size = n>m ? n:m;
Let the input of the coordinates be an array of coordinates. coord_t c[k]
struct coord_t {
int x;
int y;
};
1. My idea is to create an array of size = n>m?n:m;
2. int array[size] = {0} ; //initialize all the elements in the array to zero
for(i=0;i<k;i++)
{
array[c[i].x] = +1;
count++;
}
int tempCount =0;
for(i=0;i<k;i++)
{
if(array[i]!=0)
{
tempCount += array[i];
}
if(tempCount >= count/2)
{
break;
}
}
int x_median = i;
//similarly with y coordinate.
int array[size] = {0} ; //initialize all the elements in the array to zero
for(i=0;i<k;i++)
{
array[c[i].y] = +1;
count++;
}
int tempCount =0;
for(i=0;i<k;i++)
{
if(array[i]!=0)
{
tempCount += array[i];
}
if(tempCount >= count/2)
{
break;
}
}
int y_median = i;
coord_t temp;
temp.x = x_median;
temp.y= y_median;
return temp;
Sample Working code for MxM matrix with k points:
*Problem
Given a MxM grid . and N people placed in random position on the grid. Find the optimal meeting point of all the people.
/
/
Answer:
Find the median of all the x coordiates of the positions of the people.
Find the median of all the y coordinates of the positions of the people.
*/
#include<stdio.h>
#include<stdlib.h>
typedef struct coord_struct {
int x;
int y;
}coord_struct;
typedef struct distance {
int count;
}distance;
coord_struct toFindTheOptimalDistance (int N, int M, coord_struct input[])
{
coord_struct z ;
z.x=0;
z.y=0;
int i,j;
distance * array_dist;
array_dist = (distance*)(malloc(sizeof(distance)*M));
for(i=0;i<M;i++)
{
array_dist[i].count =0;
}
for(i=0;i<N;i++)
{
array_dist[input[i].x].count +=1;
printf("%d and %d\n",input[i].x,array_dist[input[i].x].count);
}
j=0;
for(i=0;i<=N/2;)
{
printf("%d\n",i);
if(array_dist[j].count !=0)
i+=array_dist[j].count;
j++;
}
printf("x coordinate = %d",j-1);
int x= j-1;
for(i=0;i<M;i++)
array_dist[i].count =0;
for(i=0;i<N;i++)
{
array_dist[input[i].y].count +=1;
}
j=0;
for(i=0;i<N/2;)
{
if(array_dist[j].count !=0)
i+=array_dist[j].count;
j++;
}
int y =j-1;
printf("y coordinate = %d",j-1);
z.x=x;
z.y =y;
return z;
}
int main()
{
coord_struct input[5];
input[0].x =1;
input[0].y =2;
input[1].x =1;
input[1].y =2;
input[2].x =4;
input[2].y =1;
input[3].x = 5;
input[3].y = 2;
input[4].x = 5;
input[4].y = 2;
int size = m>n?m:n;
coord_struct x = toFindTheOptimalDistance(5,size,input);
}
Your algorithm is fine, and divide the problem into two one-dimensional problem. And the time complexity is O(nlogn).
You only need to divide every groups of people into n single people, so every move to left, right, up or down will be 1 for each people. We only need to find where's the (n + 1) / 2th people stand for row and column respectively.
Consider your sample. {(-100,0,100),(100,0,100),(0,1,1)}.
Let's take the line numbers out. It's {(-100,100),(100,100),(0,1)}, and that means 100 people stand at -100, 100 people stand at 100, and 1 people stand at 0.
Sort it by x, and it's {(-100,100),(0,1),(100,100)}. There is 201 people in total, so we only need to set the location at where the 101th people stands. It's 0, and that's for the answer.
The column number is with the same algorithm. {(0,100),(0,100),(1,1)}, and it's sorted. The 101th people is at 0, so the answer for column is also 0.
The answer is (0,0).
I can think of O(n) solution for one dimensional problem, which in turn means you can solve original problem in O(n+m+G).
Suppose, people are standing like this, a_0, a_1, ... a_n-1: a_0 people at spot 0, a_1 at spot 1. Then the solution in pseudocode is
cur_result = sum(i*a_i, i = 1..n-1)
cur_r = sum(a_i, i = 1..n-1)
cur_l = a_0
for i = 1:n-1
cur_result = cur_result - cur_r + cur_l
cur_r = cur_r - a_i
cur_l = cur_l + a_i
end
You need to find point, where cur_result is minimal.
So you need O(n) + O(m) for solving 1d problems + O(G) to build them, meaning total complexity is O(n+m+G).
Alternatively you solve 1d in O(G*log G) (or O(G) if data is sorted) using the same idea. Choose the one from expected number of groups.
you can solve this in O(G Log G) time by reducing it to, two one dimensional problems as you mentioned.
And as to how to solve it in one dimension, just sort them and go through them one by one and calculate cost moving to that point. This calculation can be done in O(1) time for each point.
You can also avoid Log(G) component if your x and y coordinates are small enough for you to use bucket/radix sort.
Inspired by kilotaras's idea. It seems that there is a O(G) solution for this problem.
Since everyone agree with the two dimensional problem can be reduced to two one dimensional problem. I will not repeat it again. I just focus on how to solve the one dimensional problem
with O(G).
Suppose, people are standing like this, a[0], a[1], ... a[n-1]. There is a[i] people standing at spot i. There are G spots having people(G <= n). Assuming these G spots are g[1], g[2], ..., g[G], where gi is in [0,...,n-1]. Without losing generality, we can also assume that g[1] < g[2] < ... < g[G].
It's not hard to prove that the optimal spot must come from these G spots. I will pass the
prove here and left it as an exercise if you guys have interest.
Since the above observation, we can just compute the cost of moving to the spot of every group and then chose the minimal one. There is an obvious O(G^2) algorithm to do this.
But using kilotaras's idea, we can do it in O(G)(no sorting).
cost[1] = sum((g[i]-g[1])*a[g[i]], i = 2,...,G) // the cost of moving to the
spot of first group. This step is O(G).
cur_r = sum(a[g[i]], i = 2,...,G) //How many people is on the right side of the
second group including the second group. This step is O(G).
cur_l = a[g[1]] //How many people is on the left side of the second group not
including the second group.
for i = 2:G
gap = g[i] - g[i-1];
cost[i] = cost[i-1] - cur_r*gap + cur_l*gap;
if i != G
cur_r = cur_r - a[g[i]];
cur_l = cur_l + a[g[i]];
end
end
The minimal of cost[i] is the answer.
Using the example 5 1 0 3 to illustrate the algorithm.
In this example,
n = 4, G = 3.
g[1] = 0, g[2] = 1, g[3] = 3.
a[0] = 5, a[1] = 1, a[2] = 0, a[3] = 3.
(1) cost[1] = 1*1+3*3 = 10, cur_r = 4, cur_l = 5.
(2) cost[2] = 10 - 4*1 + 5*1 = 11, gap = g[2] - g[1] = 1, cur_r = 4 - a[g[2]] = 3, cur_l = 6.
(3) cost[3] = 11 - 3*2 + 6*2 = 17, gap = g[3] - g[2] = 2.