I have a problem which has a rather limited time constraint, and would like to see if I could get a nudge in the right direction.
Here is the problem:
You are presented with a wall with columns of different heights. Each column heights is represented as a non-zero integers.
Input state is defined using an array H of length N, containing heights of each
of the N columns on the screen, for example:
Slicing the snapshot at a given height leaves a number of solid pieces
above that height. E.g. slicing at level 2 would cut 3 solid pieces:
Slicing at level 1 would also cut 3 solid pieces:
Similarly, slicing at level 0 would return a single (one) solid piece, while slicing at level 3 wouldn't cut any pieces.
Requirement: Given an array of slice heights S of length M, containing all
levels at which a "slice" should be performed, return an array of length M containing numbers of cut pieces for each respective cut.
For example, given the input H = {2, 1, 3, 2, 3, 1, 1, 2} and S = { 0, 1, 2, 3 }, the program should return quantities {1, 3, 3, 0}, according to the examples above.
Both N and M are in the range of around 20,000, but heights in each array can reach up to 1,000,000.
Both time and space worst-case complexity for the solution cannot exceed
O(N + M + max(M) + max(N)).
The last constraint is what puzzles me: it basically means that I cannot have any nested for-loops, and I cannot seem to escape this.
Obviously, there is some clever preprocessing which needs to be done to yield final results in O(1) per slice, but I haven't been able to come up with it.
I went on to create an array of cut numbers for each slice level, and then update all of them as I iterate through H, but this turns out to be O(N*M), since I need to update all lower height levels.
Is there a data structure which would be appropriate for this task?
For each piece at a height there must be two edges intersecting that height, and by the definition of a "piece", the members of the set of such edges must all be distinct. So the number of pieces is half the number of edges in the set.
Further, the number of edges intersecting a specific height is the number of edges that have started below or at that height, minus the number of edges that have finished below or at it.
As such, we can calculate the number of pieces this way:
Create an array Accumulator of size max(S) filled with zeroes.
Iterate over H, and for each vertical edge you encounter add a +1 at the index i in Accumulator corresponding to the height of the edge's lower end, and add a -1 at the index j at corresponding to the edge's upper end. We're counting "ground level" as zero. Make sure to include the leading and trailing edges!
Iterate over Accumulator and insert in each cell the sum of all cells up to and including it (O(max(S)) time if you keep a running sum)
Divide every value in Accumulator by 2 to get the number of pieces at each height.
Read out the number of pieces corresponding to the heights in S.
Example:
The edge's endpoints, from left to right, are
0,2
1,2
1,3
2,3
2,3
1,3
1,3
0,3
So our Accumulator array looks like this:
{2, 4, 0, -6}
Which after the accumulation step, looks like this:
{2, 6, 6, 0}
Which means the part counts are
{1, 3, 3, 0}
As a warning, I've just come up with this on the spot, so while it feels correct I've no proof whether it actually is. Encouragingly, it worked on a few other token examples I tried as well.
Step 1: Maintain 3 column list (height, index_start, index_end)
Step 2: Sort the list according to height as primary key (decreasing), index_start as secondary key
Step 3: Let h be the highest height
Step 4: Merge all columns at height at least h and contiguous block
Step 5: Resulting number of blocks is blocks at height h
Step 6: h=h-1
Step 7: Go to step 4
This is the rough algo. Effectively the complexity is O(nlogn)
Related
Problem:
There are N cubes. There are M numbers. Each side of cube has number from 1 to M. You can stack one cube on another if their touching sides have same number (top side of bottom cube and bottom side of top cube has same number). Find the highest tower of cubes.
Input: number N of cubes and number M.
Example:
INPUT: N=5, M=6. Now we generate 5 random cubes with 6 sides = <1,M>.
[2, 4, 3, 1, 4, 1]
[5, 1, 6, 6, 2, 5]
[2, 5, 3, 1, 1, 6]
[3, 5, 6, 1, 3, 4]
[2, 4, 4, 5, 5, 5]
how you interpret single array of 6 numbers is up to you. Opposite sides in cube might be index, 5-index (for first cube opposite side of 4 would be 4). Opposite sides in cube might also be index and index+1 or index-1 if index%2==0 or 1 respectively. I used the second one.
Now let's say first cube is our current tower. Depending on the rotation top color might be one of 1, 2, 3, 4. If the 1 is color on top we can stack
on top of it second, third or fourth cube. All of them has color 1 on their sides. Third cube even has two sides with color 1 so we can stack it in two different ways.
I won't analyse it till the end because this post would be too long. Final answer for these (max height of the tower) is 5.
My current solution (you can SKIP this part):
Now I'm just building the tower recursively. Each function has this subproblem to solve: find highest tower given the top color of current tower and current unused cubes (or current used cubes). This way I can memoize and store results for tuple(top color of tower, array of used cubes). Despite memoization I think that in the worst case (for small M) this solution has to store M*(2^N) values (and this many cases to solve).
What I'm looking for:
I'm looking for something that would help me solve this efficiently for small M. I know that there is tile stacking problem (which uses Dynamic Programming) and tower of cubes (which uses DAG longest path) but I don't see the applicability of these solutions to my problem.
You won't find a polynomial time solution- if you did, we'd be able to solve the decision variant of the longest path problem (which is NP-Complete) in polynomial time. The reduction is as follows: for every edge in an undirected graph G, create a cube with opposing faces (u, v), where u and v are unique identifiers for the vertices of the edge. For the remaining 4 faces, assign globally unique identifiers. Solve for the tallest cube tower, this tower's height will be the length of the longest path of G, return if path length equals the queried value (yes/no).
However, you could still solve it in something like O(M^3*(N/2)!*log(N)) time (I think that bound is a bit loose, but its close). Use divide and conquer with memoization. Find all longest paths using cubes [0, N) beginning with a value B in range [0, M) and ending with a value E in range [0, M), for all possible B and E. To compute this, recurse, partitioning the cubes evenly in every possible way. Keep recursing until you hit the bottom (just one cube). Then begin merging them (by combining cube stacks that end in X with those beginning with X, for all X in [0, M). Once that's all done, at the topmost level just take the max of all the tower heights.
I'm solving one problem from past competitions in programming, so i need help, i will explain the problem in one sentence. You have an array with size of N, where N can go up to 10^5. And then in second line you have exactly N elements. So now you have to count the the ways to pick three elements from the array such that they will be in decreasing order. Here is example
N=4 and the array looks like this 190, 180, 170, 168. We have exactly four ways to pick those three elements. 1. (190, 180, 170) 2. (190,180,168) 3. (190, 170, 168) and 4. (180, 170, 168)
I think that this should be solved with segment tree but i don't know with which argument should i create the tree. Thanks in advance.
We can assume that all numbers are in the [0, n - 1] range (otherwise, we can 'compress' them).
Let's fix the position of the middle element in the triple. Now we can count the number of greater elements to the left from it and multiply by the number of smaller elements to the right from it.
How to count the number of greater elements with smaller indices? Here is a pseudo code that explains it:
tree = SegmentTree(0, n - 1) // for sum and add operations
for i = 0 ... n - 1
greaterLeft[i] = tree.getSum(a[i] + 1, n - 1)
tree.update(a[i], 1)
Note that we need updates in a point and a sum of a range. A binary index tree can do it efficiently (it is easier to implement than a segment tree).
Let R1,...Rn be n axis-aligned rectangles in the plane for which the corners are points in the n×n-grid. Thus, for each rectangle Ri the four corners are points where both coordinates are integers in {1,...n}.
Now I want to sort these rectangles R1,...Rn by there increasing area in O(n) time.
I have an algorithm to sort them in O(n*log n). But how can it be done in O(n) ?
Using O(n*log n) we can do this :
Calculate all the areas, and then sort using any standard sorting algorithm like Quick sort
I guess some per-processing will be required, so that we can sort in O(n) , because we are given some pre-conditions which can help. I just want algorithm, no code required.
Since the keys (areas) of the rectangles are integers, the task can be completed in O(n) time using a counting sort. You know the minimum key is 0 and maximum key for the problem is n^2, so in the algorithm k=n^2+1. The algorithm completes in three passes: computing histogram, computing starting and ending indexes for each key, then copying the data to the output array, preserving order of inputs with equal keys so that the sort is stable. Each pass is O(n) so altogether the algorithm is O(n).
Example: Suppose n is 3. k is one more than the largest key that appears in the data, so that all keys fit in the range [0..k-1] inclusive, i.e., k is 10. You make a histogram h by setting up an array of 0s with index from 0 to k-1, and you fill the histogram by walking through your set of rectangles and just count them up. Say there are 2 with area 1, 5 with area 2, and 2 with area 4. h = [0, 2, 5, 0, 2, 0, 0, 0, 0, 0]. Then the starting indexes are immediately computed from the histogram as 0, 0, 2, 7, 7, 9, 9, 9, 9, 9. Any rectangle with area 0 goes into output array starting at 0. Any rectangle with area 1 goes into output array starting at 0 (and increment that number when you put a rectangle of area 1 into output). Any rectangle with area 2 goes into output array starting at 2. Any rectangle with area 3 goes into output array starting at 7. Any rectangle with area 4 goes into output array starting at 7.
A Toeplitz matrix "is a matrix in which each descending diagonal from left to right is constant." Given a binary matrix M, is there an efficient algorithm to determine if there is a permutation of the rows which makes it Toeplitz?
For example, set
M= [0 1 1]
[1 1 0]
[1 0 1]
If you swap the first and second row you get
[1 1 0]
[0 1 1]
[1 0 1]
which is Toeplitz.
In python you can make a random binary matrix as follows.
n = 10
h = 10
M = np.random.randint(2, size=(h,n))
I would like to apply the test to M.
(Note the matrix M does not need to be square.)
This problem can be solved in linear O(h*w) time, where h is number of rows and w is number of columns.
Construct a graph where each vertex corresponds to (w-1)-length substring which may be either prefix or suffix of some row in the matrix. One vertex may correspond to several duplicate substrings. Connect these vertexes with h edges. Each edge corresponds to row of the matrix. It is directed from the vertex corresponding to this row's prefix to the vertex corresponding to this row's suffix.
To determine if some row permutation is a Toeplitz matrix, it is enough to check if constructed graph is Eulerian graph. To find permutation itself, it is enough to find Eulerian path in this graph.
We need some efficient way to interconnect vertexes and edges. Straightforward approach assumes comparing each row-substring pair. This is not very interesting because of O(h2*w) time complexity.
Building Generalized suffix tree (or suffix array) for rows of the matrix needs only O(h*w) time. And this tree allows to interconnect vertexes and edges also in linear time: each internal node with depth w-1 represents some (w-1)-length substring (vertex); each leaf attached to this node represents some row's suffix (incoming edge); and each leaf attached to this node's children represents some row containing this substring as a prefix (outgoing edge).
Other alternative is to use hash map. With (w-1)-length substring of matrix row as a key and pair of lists of row indexes (for rows where this substring is prefix/suffix) as a value. Comparing to suffix tree/array approach, this allows simpler implementation, needs less memory (each key needs only space for hash value and pointer to beginning of the substring), should work faster (on average), but has inferior worst-case complexity: O(h2*w).
One simple-minded approach that would work for small matrices is:
Sort the rows of M
For each choice of start row
For each choice of end row
construct a Toeplitz matrix T from the given start and end row
Sort the rows of T and compare to M
If you find a match then T is a permutation of M that is Toeplitz
This is based on the fact that a Toeplitz matrix is uniquely defined once you know the start and end rows.
However, this approach is not particularly efficient.
Example Python Code
M= [[0, 1, 1],
[1, 1, 0],
[1, 0, 1]]
n=len(M)
M2 = sorted(M)
for start in M2:
for end in M2:
v = end+start[1:]
T = [v[s:s+n] for s in range(n-1,-1,-1)]
if sorted(T)==M2:
print 'Found Toeplitz representation'
print T
prints
Found Toeplitz representation
[[0, 1, 1],
[1, 0, 1],
[1, 1, 0]]
Found Toeplitz representation
[[1, 0, 1],
[1, 1, 0],
[0, 1, 1]]
Found Toeplitz representation
[[1, 1, 0],
[0, 1, 1],
[1, 0, 1]]
You can conduct a pre-preliminary check for elimination condition:
Find out the column-wise sum of all the columns of the matrix.
Now in any permutation of rows, the values in the columns shall stay in the same column.
So the difference between the sum of any two neighbouring columns should be at the maximum 1.
Also, if i and i+1 are two neighbouring columns, then:
If sum(i+1) = sum(i) + 1, then we know that bottom-most element in column i should be 0 and top-most element in column (i+1) should be 1.
If sum(i+1) = sum(i) - 1, then we know that bottom-most element in column i should be 1 and top-most element in column (i+1) should be 0.
If sum(i+1) = sum(i), then we know that bottom-most element in column i should be equal to top-most element in column (i+1).
You can also conduct a similar check by summing the rows and see if there is any permutation in which the difference between sum of any two neighbouring rows is at most one.
Ofcourse, you will still have to conduct some combinatorial search, but the above filter may reduce the search scenarios.
This is because you now have to search for a pair of (candidate top and bottom) rows that satisfies the above 3 conditions for each pair of neighbouring columns.
Also, this optimization shall not be very helpful if the number of rows is much larger than the number of columns.
How to find, in a binary string, the longest substring where the balance, i.e. the difference between the number of ones and zeros, is >= 0?
Example:
01110000010 -> 6: 011100
1110000011110000111 -> 19: entire string
While this problem looks very similar to the Maximum Value Contiguous Subsequence (Maximum Contiguous Sum) problem, a dynamic programming solution doesn't seem to be obvious. In a divide-and-conquer approach, how to do the merging? Is an "efficient" algorithm possible after all? (A trivial O(n^2) algorithm will just iterate over all substrings for all possible starting points.)
This is a modified variant of Finding a substring, with some additional conditions. The difference is that in the linked question, only such substrings are allowed where balance never falls below zero (looking at the string in either forward or backward direction). In the given problem, balance is allowed to fall below zero, provided it recovers at some later stage.
I have a solution that requires O(n) additional memory and O(n) time.
Let's denote the 'height' of an index h(i) as
h(i) = <number of 1s in the substring 1..i> - <number of 0s in the same substring>
The problem can now be reformulated as: find i and j such as h(i) <= h(j) and j-i -> max.
Obviously, h(0) = 0, and if h(n) = 0, then the solution is the entire string.
Now let's compute the array B so that B[x] = min{i: h(i) = -x}. In other words, let B[x] be the leftmost index i at which h(i)= -x.
The array B[x] has a length of at most n, and is computed in one linear pass.
Now we can iterate over the original string and for each index i compute the length of the longest sequence with non-negative balance that ends on i as follows:
Lmax(i) = i - B[MIN{0, h(i)}]
The largest Lmax(i) across all i will give you the desired length.
I leave the proof as an exercise :) Contact me if you can't figure it out.
Also, my algorithm needs 2 passes of the original string, but you can collapse them into one.
This can be answered quite easily in O(n) using "height array", representing the number of 1's relative to the number of 0's. Like my answer in the linked question.
Now, instead of focusing on the original array, we now focus on two arrays indexed by the heights, and one will contain the smallest index such height is found, and the other will contain the largest index such height is found. Since we don't want a negative index, we can shift everything up, such that the minimum height is 0.
So for the sample cases (I added two more 1's at the end to show my point):
1110000011010000011111
Array height visualization
/\
/ \
/ \
\ /\/\ /
\/ \ /
\ /
\ /
\/
(lowest height = -5)
Shifted height array:
[5, 6, 7, 8, 7, 6, 5, 4, 3, 4, 5, 4, 5, 4, 3, 2, 1, 0, 1, 2, 3]
Height: 0 1 2 3 4 5 6 7 8
first_view = [17,16,15, 8, 7, 0, 1, 2, 3]
last_view = [17,18,19,20,21,22, 5, 4, 3]
note that we have 22 numbers and 23 distinct indices, 0-22, representing the 23 spaces between and padding the numbers
We can build the first_view and last_view array in O(n).
Now, for each height in the first_view, we only need to check every larger heights in last_view, and take the index with maximum difference from the first_view index. For example, from height 0, the maximum value of index in larger heights is 22. So the longest substring starting at index 17+1 will end at index 22.
To find the maximum index on the last_view array, you can convert it to a maximum to the right in O(n):
last_view_max = [22,22,22,22,22,22, 5, 4, 3]
And so finding answer is simply subtracting first_view from last_view_max,
first_view = [17,16,15, 8, 7, 0, 1, 2, 3]
last_view_max = [22,22,22,22,22,22, 5, 4, 3]
result = [ 5, 6, 7,14,15,22, 4, 2, 0]
and taking the maximum (again in O(n)), which is 22, achieved from starting index 0 to ending index 22, i.e., the whole string. =D
Proof of correctness:
Suppose that the maximum substring starts at index i, ends at index j.
If the height at index i is the same as the height at index k<i, then k..j would be a longer substring still satisfying the requirement. Therefore it suffices to consider the first index of each height. Analogously for the last index.
Compressed quadratic runtime
We will be looking for (locally) longest substrings with balance zero, starting at the beginning. We will ignore strings of zeros. (Corner cases: All zeros -> empty string, balance never reaches zero again -> entire string.) Of these substrings with balance zero, all trailing zeros will be removed.
Denote by B a substring with balance > 0 and by Z a substring with only zeros. Each input string can be decomposed as follows (pseudo-regex notation):
B? (Z B)* Z?
Each of the Bs is a maximum feasible solution, meaning that it cannot be extended in either direction without reducing balance. However, it might be possible to collapse sequences of BZB or ZBZ if the balance is still larger than zero after collapsing.
Note that it is always possible to collapse sequences of BZBZB to a single B if the ZBZ part has balance >= 0. (Can be done in one pass in linear time.) Once all such sequences have been collapsed, the balance of each ZBZ part is below zero. Still, it is possible that there exist BZB parts with balance above zero -- even that in a BZBZB sequence with balance below zero both the leading and trailing BZB parts have balance over zero. At this point, it seems to be difficult to decide which BZB to collapse.
Still quadratic...
Anyway, with this simplified data structure one can try all Bs as starting points (possibly extending to the left if there's still balance left). Run time is still quadratic, but (in practice) with a much smaller n.
Divide and conquer
Another classic. Should run in O(n log n), but rather difficult to implement.
Idea
The longest feasible substring is either in the left half, in the right half, or it passes over the boundary. Call the algorithm for both halves. For the boundary:
Assume problem size n. For the longest feasible substring that crosses the boundary, we are going to compute the balance of the left-half part of the substring.
Determine, for each possible balance between -n/2 and n/2, in the left half, the length of the longest string that ends at the boundary and has this (or a larger) balance. (Linear time!) Do the same for the right half and the longest string that starts at the boundary. The result is two arrays of size n + 1; we reverse one of them, add them element-wise and find the maximum. (Again, linear.)
Why does it work?
A substring with balance >= 0 that crosses the boundary can have balance < 0 in either the left or the right part, if the other part compensates this. ("Borrowing" balance.) The crucial question is how much to borrow; we iterate over all potential "balance credits" and find the best trade-off.
Why is this O(n log n)?
Because merging (looking at boundary-crossing string) takes only linear time.
Why is merging O(n)?
Exercise left to the reader.
Dynamic programming -- linear run time (finally!)
inspired by this blog post. Simple and efficient, one-pass online algorithm, but takes some time to explain.
Idea
The link above shows a different problem: Maximum subsequence sum. It cannot be mapped 1:1 to the given problem, here a "state" of O(n) is needed, in contrast to O(1) for the original problem. Still, the state can be updated in O(1).
Let's rephrase the problem. We are looking for the longest substring in the input where the balance, i.e. the difference between 0's and 1's, is greater than zero.
The state is similar to my other divide-and-conquer solution: We compute, for each position i and for each possible balance b the starting position s(i, b) of the longest string with balance b or greater that ends at position i. That is, the string that starts at index s(i, b) + 1 and ends at i has balance b or greater, and there is no longer such string that ends at i.
We find the result by maximizing i - s(i, 0).
Algorithm
Of course, we do not keep all s(i, b) in memory, just those for the current i (which we iterate over the input). We start with s(0, b) := 0 for b <= 0 and := undefined for b > 0. For each i, we update with the following rule:
If 1 is read: s(i, b) := s(i - 1, b - 1).
If 0 is read: s(i, b) := s(i - 1, b + 1) if defined, s(i, 0) := i if s(i - 1, 1) undefined.
The function s (for current i) can be implemented as a pointer into an array of length 2n + 1; this pointer is moved forward or backward depending on the input. At each iteration, we note the value of s(i, 0).
How does it work?
The state function s becomes effective especially if the balance from the start to i is negative. It records the earliest start point where zero balance is reached, for all possible numbers of 1s that have not been read yet.
Why does it work?
Because the recursive definition of the state function is equivalent to its direct definition -- the starting position of the longest string with balance b or greater that ends at position i.
Why is the recursive definition correct?
Proof by induction.