I have an array with 600x600 integer values.
The values represents a circle.
For example: 0 is outside, >=1 is inside the circle.
Here is a short example:
0000110000000
0001111000000
0011111200000
0112112110000
1111111111000
0111411110000
0011131100000
0000110000000
0000000000000
0000000000000
The position and the size of the circle in the array differs.
Now, I am looking for a fast algorithm to find the center and the radius of the circle.
Fast because I have to process many arrays.
Superimpose a grid, walk it, (small matrices: every row and column, large matrices every Xth row and column) and find the points where the change (0 -> >=1 or vice versa) happens.
If your grid is symetrical and dense enough, the average of these points is equal to the center.
The average distance ( sqrt(sqr(x-xm)+sqr(y-ym))) of the found points and the center is a measure for the radius.
Walking rows alone might be enough for larger datasets, and you scan only Xth line. If you work with real images, you might have to cater for noise, and variations in brightness.
It is possible to do it faster. Actually according to your sample it does not matter (and we must not estimate) if there is a circle or a square.
Assuming that there is a two-dimention 0-based array the radius will be simply the the count of non-zero (not empty) rows (or columns) divided by 2.
Algo.
Find the number of the non-zero rows and their first (top) index.
Divide this number by two and add the number of zero rows with indexes less then the lowest non-zero row. Now you know the radius and y coordinate.
Find the first(left) non-zero column and add the radius to its index. Now you have the x coordinate.
In the provided example.
The number of non-zero rows is 8. The radius is 8 / 2 = 4. There are 0 rows to the top before the non-zero rows (in other words the ID of the first non-zero row is 0). So the y coordinate is 0 + 4 = 4.
There are 0 empty columns to the left from the first non-zero column (or the ID of the first non-zero column is 0). The x coordinate will be 4 + 0 = 4.
To know if the column is zero you can use some function like this:
IsEmpty := true;
for i := 0 to High(Column) do
if Column[i] > 0 then
begin
IsEmpty := false;
Break;
end;
Related
I'm having hard time with this one:
I need to write a function in C that recieving a binary array and his size, and the function should calculate and replace the current values with the distance (by indexes) of each 1 to the closest 0.
for example: if the function recieve that array {1,1,0,1,1,1,0,1} then the new values of the array should be {2,1,0,1,2,1,0,1}. It is known that the input has atleast 1 zero.
So the first step I tought about was to locate pair of zeros (or just 1 if there is only 1) and set them as 2 indexes (z1, z2). Then I set another index i
that check everytime which zero is the closest to him (absolute value) and then the diffrence between i and z1 or z2 would be the new value.
I have the plan but things are not going exactly as I planned. Basicly I deleted the code (it wasn't good anyway) so I would appreciate any help. thanks!
This problem is based on two things
Keep an array left[i] which has the distance of nearest 0 from index i from left to right.
Keep an array right[i] which has the distance of nearest 0 from index i from right to left.
Both can be calculate in single loop iteration. O(n).
Then for each position get the minimum value of left[i] and right[i]. That will be the answer for 1 staying in position i.
Overall the time complexity is O(n).
I recently came through an interesting coding problem, which is as follows:
There are n boxes, let us assume this is an array of n boxes.
For each index i of this array, three values are given -
1.) Weight(i)
2.) Left(i)
3.) Right(i)
left(i) means - if weight[i] is chosen, we are not allowed to choose left[i] elements from the left of this ith element.
Similarly, right[i] means if arr[i] is chosen, we are not allowed to choose right[i] elements from the right of it.
Example :
Weight[2] = 5
Left[2] = 1
Right[2] = 3
Then, if I pick element at position 2, I get weight of 5 units. But, I cannot pick elements at position {1} (due to left constraint). And cannot pick elements at position {3,4,5} (due to right constraint).
Objective - We need to calculate the maximum sum of the weights we can pick.
Sample Test Case :-
**Input: **
5
2 0 3
4 0 0
3 2 0
7 2 1
9 2 0
**Output: **
13
Note - First column is weights, Second column is left constraints, Third column is right constraints
I used Dynamic Programming approach(similar to Longest Increasing Subsequence) to reach a O(n^2) solution. But, not able to think of a O(n*logn) solution. (n can be up to 10^5.)
I also tried to use priority queue, in which elements with lower value of (right[i] + i) are given higher priority(assigned higher priority to element with lower value of "i", in case primary key value is equal). But, it is also giving timeout error.
Any other approach for this? or any optimization in priority queue method? I can post both of my codes if needed.
Thanks.
One approach is to use a binary indexed tree to create a data structure that makes it easy to do two operations in O(logn) time each:
Insert number into an array
Find maximum in a given range
We will use this data structure to hold the maximum weight that can be achieved by selecting box i along with an optimal selection of boxes to the left.
The key is that we will only insert values into this data structure when we reach a point where the right constraint has been met.
To find the best value for box i, we need to find the maximum value in the data structure for all points up to location i-left[i], which can be done in O(logn).
The final algorithm is to loop over i=0..n-1 and for each i:
Compute result for box i by finding maximum in range 0..(i-left[i])
Schedule the result to be added when we reach location i+right[i]
Add any previously scheduled results into our data structure
The final result is the maximum value in the whole data structure.
Overall, the complexity is o(nlogn) because each value of i results in one lookup and one update operation.
I have a matrix M:
M=rand(n,m)
and an array K of length m^n
K=zeros(m^n,1)
The array K is filled in with the values obtained by summing up the values of the matrix M across n rows for all possible m^n vertical combination of cells. An auxiliary array Index of length m^n contains index references to the cell combinations so that the column indices of the Index array indicate the rows of matrix M and the values of the Index array – the columns of the matrix M. In the example below for 4x3 matrix, the second row {1,1,1,2} of the Index array corresponds to the combination of cells M(1,1), M(2,1),M(3,1) and M(4,2) etc:
Index =
1 1 1 1
1 1 1 2
1 1 1 3
1 1 2 1
…
This index referencing is then used to calculate the values (sum) of each cell combination which are stored in K:
for i=1:m^(n)
for j=1:n
K(i)= K(i)+M(j,Index(i,j))
end
end
Until this point it works fine. What I need, however, is to introduce an “if” condition so that if any of the cell of matrix M is equal to zero, than the value of any combination containing this zero-value (cell(s)) will be also zero. I have tried to introduce it within the for-loop:
Assume
M(1,1)=0
M(3,1)=0
Then
for i=1:m^(n)
for j=1:n
if M(j,Index(i,j))~=0
K(i)= K(i)+M(j,Index(i,j))
else
K(i)=0
end
end
end
This solution does not seem to work because it fails to identify the cell combinations associated with zero-value cells and I cannot figure out the way around it. Does anyone know how to solve this? Thank you!
If I understand your explanation correctly...
Once your code has found a matrix element equal to zero it should break out of the inner for loop instead of continuing to sum. Try this:
for i=1:m^(n)
for j=1:n
if M(j,Index(i,j))~=0
K(i)= K(i)+M(j,Index(i,j))
else
K(i)=0
break
end
end
end
You should also be careful that for floating point numbers, such as the ones yielded by rand, they may not quite be equal to zero.
You have a matrix of 0 and 1 for example:
1 1 1 0
1 1 1 0
1 1 1 0
1 1 1 1
0 1 1 1
1 0 1 1
A square is placed at position (0,0), find the size of the largest square of all 1s that be move from the upper left corner to the lower right corner. The square can only move down and to the right and only over elements which are 1.
In this example the size of the largest square is 2. The indexes of elements in the square are (0,0), (0,1), (1,0), (1,1).
I'm not sure how to solve this problem. I think first, you need to find the all the squares in the upper left corner and all squares in lower right corner. If the move is possible, then there must be squares in these 2 positions that are the same size. Then only attempt to move squares in the left corner that are equal in size to square in right corner. But I'm not sure how to go about finding the squares and checking if they can be moved.
You can use dynamic programming.
Let's assume that max_size(i, j) is the size of the largest square that can stay in a (i, j) cell(possibly 0)(stays in means that its top left corner is located in this cell). We can compute this value in a naive way(by iteratively increasing the size of the square and checking that it does not touch any 0). If a naive solution is not feasible, we can use binary search over the answer and prefix sums to get an O(log n) time per cell.
Let's say that f(i, j) is the largest square that can reach the (i, j) cell. The base case: f(0, 0) = max_size(0, 0)(we can always reach the the top left corner). For the other cells, it can be computed in the following way(I omit corner cases here):
for i <- 0 ... n - 1:
for j <- 0 ... m - 1:
f(i, j) = min(max_size(i, j), max(f(i - 1, j), f(i, j - 1)))
The answer is the largest f(i, j) such that i + f(i, j) - 1 = n - 1 and j + f(i, j) - 1 = m - 1.
The time complexity is O(n * m * log(min(n, m))).
Your first step is right: find the largest square that fits into both the lower right and the upper left.
Then, start with a square of that size in the upper left. Try the paths to the lower right breadth-first. After each step, you check whether the square still fits, otherwise reduce its size. You will then often arrive at a given place from two directions (from above and from the left). Continue from there with the bigger size (this unification step is why you should go breadth-first, this is also called "dynamic programming").
In your example, you start with an array of size 2 at (0 0), but let's say that you start with size 3 for demonstration purposes. So, layer 0 is a single square of size 3 at (0 0). Moving down is no problem, but moving to the right steps on some zeroes, so you have to reduce the size. Layer 1 is thus a list of two squares: one of size 3 at (1 0) and one of size 2 at (0 1). Next layer: move right from (0 1), need to reduce to size 1 at (0 2); move down from (0 1) as well as right from (1 0), both arrive at (1 1), from above with size 2, from left needs to reduce to size 2, so size 2; move down from (1 0), reduce to size 2. So, Layer 2 is a list of three squares: one of size 2 at (2 0), one of size 2 at (1 1), and one of size 1 at (0 2). I think this suffices as a demonstration.
You have reached a solution when you complete a layer that contains a square that touches the lower right. You can tell that there is no solution when all your squares are size 0.
Brute force solution
If your matrix has size N x M, every path of a square of size S x S from top left to bottom right is N + M - 2S 'steps' (movements to the right or left) long, where N - S steps will go downwards and M - S steps rightwards. So if we disregard the values on the matrix, there will be (N + M - 2S) choose (N - S) possible paths.
So if the matrix isn't too large, it might be feasible to just try all these paths for a given square size S and test them for compliance with the square placement rules (whether in each step, the square only covers 1s and no 0s.)
Do this for each S from 1 to min(N,M), and keep track of the values of S for which you can find at least one valid path.
Then, just take the maximum of these S values and you've got the wanted result.
So brute-forcing will (eventually) give you the correct value.
Optimizations
Off course, this isn't as efficient as could be, which will lead to enormous runtimes for large matrices. But we can improve step by step, by looking into what steps are unneccesary.
One valid path for a given square size suffices
If you've found a valid path for a given square size S, you don't have to look for more paths for the same square size and can skip to testing other, yet untested square sizes.
One invalid step kills the whole path
If any step of a path leads to an invalid placement, you don't have to check the other steps. You already know you can't use the whole path.
Don't do double work
Each of the (N-S) * (M-S) possible placements of a square with given size S will be part of several paths. Instead of checking each placement's validity for each path it is part of, do it just once for each placement and store the result in a (N-S) x (M-S) matrix.
Bigger won't fit better
If you've tested all paths for a given square size S, and none of them was valid, you don't have to test larger S at all, as you know there won't be valid paths for them.
Smaller won't fit worse
If you've found a path for a given square size S, you can be sure that all smaller square sizes will have at least one valid path, too, so you don't have to test them. (You wouldn't have to, anyway, as you're looking for the maximum S with at least one valid path.)
Bisection?
Combining the two realizations above, you'll come to the conclusion that it won't be optimal to test sizes S in order, be it increasing or decreasing. Rather, you could start somewhere in-between and —depending on the result for that S— rule out all smaller or all larger values for S. Whether it is optimal to start exactly in the middle (at min(N,M) / 2), I'm not sure, though, as the number of paths to search for a given S (remember the binomial coefficient formula in the "Brute force" section above) depends on the size of S.
Parallelization
Almost every level of the brute force algorithm has several steps that are independent of each other and could be executed in parallel.
More?
I'm sure even with all of the above implemented, there's still room for more optimization, even if I can't think of any right now.
I came across a problem of Matrices but was trying to figure out the optimal solution.
Problem statement is the question topic itself.
Further see below
Example
Input matrix
0 1 1 1
0 0 1 1
1 1 1 1 // this row has maximum 1s
0 0 0 0
Output: 2
My Solution : Now since rows are sorted, i thought of performing binary search in each row with the first occurrence of 1, and then count of 1 will be total number of columns minus index of 1st 1.
This will do it in O(m*logn), but I was curious to know the logic if this could be done in linear time.
Thank you!
Start a cursor in the top right. In each row, step left until you reach the last 1 in the row. Then step down. If you step down and the cursor points to a 0, step down again. Never go right. You're looking for the row that has a 1 furthest to the left, so you never need to look to the right. The runtime is O(n+m), since you go through every row, stepping down m times, and you make a total of n steps left at most. Here's some pseudocode, assuming that the matrix is a list of lists:
bestrow = 0
leftmost = matrix.width
for i = matrix.height to 0:
row = matrix[i]
while row[leftmost - 1] == 1:
leftmost--
bestrow = i
return bestrow
If you translate the code literally, you may have problems with a matrix of all 0's, or if some row has all 1's. These are pretty easy to deal with, and the point of the pseudocode is just to communicate the general algorithm.
The solution for this problem depends on the number of elements in each row and the number of columns.
Here is an approach.
Step 1:
Simple do a binary && operation on all elements in each column until you get a true which means we found a column which has at least one one. This take max n steps where n is number of columns.
Step 2:
Now do a search for one from top to bottom in that column which gives you the row with max number of ones. This takes max of m steps.where m is number of rows
So overall it takes O(m+n) steps
It also helps you find multiple rows if any with the same property