Skyline of Buildings - algorithm

I'm trying to understand the skyline problem. Given n rectangular building and we need to compute the skyline. I have trouble in understanding the output for this problem.
Input: (1,11,5), (2,6,7), (3,13,9), (12,7,16), (14,3,25), (19,18,22), (23,13,29), (24,4,28) }
Output Skylines: (1, 11), (3, 13), (9, 0), (12, 7), (16, 3), (19, 18), (22, 3), (25, 0)
The output is pair (xaxis, height). Why is the third pair (9,0)? If we see the skyline graph, the x-axis value 9 has height of 13, not 0. Why is it showing 0? In other words, if we take the first building (input (1,11,5)), the output is (1, 11), (5, 0). Can you guys explain why it is (5,0) instead of (5,11)?

Think of the rooftop intervals as closed on the left and open on the right.

Your output does not signify "at x the height is y", but rather "at x the height changes to y".

using the sweep line algorithm; here is my python version solution:
class Solution:
# #param {integer[][]} buildings
# #return {integer[][]}
def getSkyline(self, buildings):
if len(buildings)==0: return []
if len(buildings)==1: return [[buildings[0][0], buildings[0][2]], [buildings[0][1], 0]]
points=[]
for building in buildings:
points+=[[building[0],building[2]]]
points+=[[building[1],-building[2]]]
points=sorted(points, key=lambda x: x[0])
moving, active, res, current=0, [0], [],-1
while moving<len(points):
i=moving
while i<=len(points):
if i<len(points) and points[i][0]==points[moving][0]:
if points[i][1]>0:
active+=[points[i][1]]
if points[i][1]>current:
current=points[i][1]
if len(res)>0 and res[-1][0]==points[i][0]:
res[-1][1]=current
else:
res+=[[points[moving][0], current]]
else:
active.remove(-points[i][1])
i+=1
else:
break
if max(active)<current:
current=max(active)
res+=[[points[moving][0], current]]
moving=i
return res

static long largestRectangle(int[] h) {
int k=1;
int n=h.length;
long max=0;
while(k<=n){
long area=0;
for(int i=0;i<n-k+1;i++){
long min=Long.MAX_VALUE;
for(int j=i;j<i+k;j++){
//System.out.print(h[j]+" ");
min=Math.min(h[j],min);
}
// System.out.println();
area=k*min;
//System.out.println(area);
max=Math.max(area,max);
}
//System.out.println(k);
k++;
}
return max;
}

Related

find all combinations with non-overlapped regions

Within a super-region S, there are k small subregions. The number k can be up to 200. There may be overlap between subregions. I have millions of regions S.
For each super-region, my goal is to find out all combinations in which there are 2 or more non-overlapped subregions.
Here is an example:
Super region: 1-100
Subregions: 1-8, 2-13, 9-18, 15-30, 20-35
Goal:
Combination1: 1-8, 9-18
Combination2: 1-8, 20-35
Combination3: 1-8, 9-18, 20-35
Combination4: 1-8, 15-30
...
Number of subsets might be exponential (max 2^k), so there is nothing wrong to traverse all possible independent subsets with recursion. I've used linear search of the next possible interval, but it is worth to exploit binary search.
def nonovl(l, idx, right, ll):
if idx == len(l):
if ll:
print(ll)
return
#find next non-overlapping interval without using l[idx]
next = idx + 1
while next < len(l) and right >= l[next][0]:
next += 1
nonovl(l, next, right, ll)
#find next non-overlapping interval after using l[idx]
next = idx + 1
right = l[idx][1]
while next < len(l) and right >= l[next][0]:
next += 1
nonovl(l, next, right, ll + str(l[idx]))
l=[(1,8),(2,13),(9,18),(15,30),(20,35)]
l.sort()
nonovl(l, 0, -1, "")
(20, 35)
(15, 30)
(9, 18)
(9, 18)(20, 35)
(2, 13)
(2, 13)(20, 35)
(2, 13)(15, 30)
(1, 8)
(1, 8)(20, 35)
(1, 8)(15, 30)
(1, 8)(9, 18)
(1, 8)(9, 18)(20, 35)

Sorting vector of x/y coordinates

I have a vector of (u32, u32) tuples which represent coordinates on a 10 x 10 grid. The coordinates are unsorted. Because the standard sort function also didn't yield the result I wanted, I wrote a sort function like this for them:
vec.sort_by(|a, b| {
if a.0 > b.0 { return Ordering::Greater; }
if a.0 < b.0 { return Ordering::Less; }
if a.1 > b.1 { return Ordering::Greater; }
if a.1 < b.1 { return Ordering::Less; }
return Ordering::Equal;
});
The resulting grid for my custom function looks like this:
(0/0) (0/1) (0/2) (0/3) (0/4) (0/5) (0/6) (0/7) (0/8) (0/9)
(1/0) (1/1) (1/2) (1/3) (1/4) (1/5) (1/6) (1/7) (1/8) (1/9)
(2/0) (2/1) (2/2) (2/3) (2/4) (2/5) (2/6) (2/7) (2/8) (2/9)
...
(9/0) (9/1) (9/2) (9/3) (9/4) (9/5) (9/6) (9/7) (9/8) (9/9)
This is not what I want, because the lower left should start with (0/0) as I would expect on a mathematical coordinates grid.
I probably can manage to add more cases to the sort algorithm, but is there an easier way to do what I want besides writing a big if .. return Ordering ...; block?
You didn't show how you are populating or printing your tuples, so this is a guess. Flip around and/or negate parts of your coordinates. I'd also recommend using sort_by_key as it's easier, as well as just reusing the existing comparison of tuples:
fn main() {
let mut points = [(0, 0), (1, 1), (1, 0), (0, 1)];
points.sort_by_key(|&(x, y)| (!y, x));
println!("{:?}", points);
}
Adding an extra newline in the output:
[(0, 1), (1, 1),
(0, 0), (1, 0)]
Originally, this answer suggested negating the value ((-y, x)). However, as pointed out by Francis Gagné, this fails for unsigned integers or signed integers when the value is the minimum value. Negating the bits happens to work fine, but is a bit too "clever".
Nowadays, I would use Ordering::reverse and Ordering::then for the clarity:
fn main() {
let mut points = [(0u8, 0u8), (1, 1), (1, 0), (0, 1)];
points.sort_by(|&(x0, y0), &(x1, y1)| y0.cmp(&y1).reverse().then(x0.cmp(&x1)));
println!("{:?}", points);
}
[(0, 1), (1, 1),
(0, 0), (1, 0)]

Find the maximum possible area

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

top down ranges merge?

I want to merge some intervals like this:
>>> ranges = [(30, 45), (40, 50), (10, 50), (60, 90), (90, 100)]
>>> merge(ranges)
[(10, 50), (60, 100)]
I'm not in cs field. I know how to do it by iteration, but wonder if there's a more efficient "top-down" approach to merge them more efficiently, maybe using some special data structure?
Thanks.
Interval tree definitely works, but it is more complex than what you need. Interval tree is an "online" solution, and so it allows you to add some intervals, look at the union, add more intervals, look again, etc.
If you have all the intervals upfront, you can do something simpler:
Start with the input
ranges = [(30, 45), (40, 50), (10, 50)]
Convert the range list into a list of endpoints. If you have range (A, B), you'll convert it to two endpoints: (A, 0) will be the left endpoint and (B, 1) wil be the right endpoint.
endpoints = [(30, 0), (45, 1), (40, 0), (50, 1), (10, 0), (50, 1)]
Sort the endpoints
endpoints = [(10, 0), (30, 0), (40, 0), (45, 1), (50, 1), (50, 1)]
Scan forward through the endpoints list. Increment a counter when you see a left endpoint and decrement the counter when you see a right endpoint. Whenever the counter hits 0, you close the current merged interval.
This solution can be implemented in a few lines.
Yeah, the efficient way to do it is to use an interval tree.
The following algorithm in C# does what you want. It uses DateTime interval ranges, but you can adapt it however you like. Once the collection is sorted in ascending start order, if the start of the next interval is at or before the end of the previous one, they overlap, and you extend the end time outward if needed. Otherwise they don't overlap, and you save the prior one off to the results.
public static List<DateTimeRange> MergeTimeRanges(List<DateTimeRange> inputRanges)
{
List<DateTimeRange> mergedRanges = new List<DateTimeRange>();
// Sort in ascending start order.
inputRanges.Sort();
DateTime currentStart = inputRanges[0].Start;
DateTime currentEnd = inputRanges[0].End;
for (int i = 1; i < inputRanges.Count; i++)
{
if (inputRanges[i].Start <= currentEnd)
{
if (inputRanges[i].End > currentEnd)
{
currentEnd = inputRanges[i].End; // Extend range.
}
}
else
{
// Save current range to output.
mergedRanges.Add(new DateTimeRange(currentStart, currentEnd));
currentStart = inputRanges[i].Start;
currentEnd = inputRanges[i].End;
}
}
mergedRanges.Add(new DateTimeRange(currentStart, currentEnd));
return mergedRanges;
}

Algorithm to generate all unique permutations of fixed-length integer partitions?

I'm searching for an algorithm that generates all permutations of fixed-length partitions of an integer. Order does not matter.
For example, for n=4 and length L=3:
[(0, 2, 2), (2, 0, 2), (2, 2, 0),
(2, 1, 1), (1, 2, 1), (1, 1, 2),
(0, 1, 3), (0, 3, 1), (3, 0, 1), (3, 1, 0), (1, 3, 0), (1, 0, 3),
(0, 0, 4), (4, 0, 0), (0, 4, 0)]
I bumbled about with integer partitions + permutations for partitions whose length is lesser than L; but that was too slow because I got the same partition multiple times (because [0, 0, 1] may be a permutation of [0, 0, 1] ;-)
Any help appreciated, and no, this isn't homework -- personal interest :-)
Okay. First, forget about the permutations and just generate the partitions of length L (as suggested by #Svein Bringsli). Note that for each partition, you may impose an ordering on the elements, such as >. Now just "count," maintaining your ordering. For n = 4, k = 3:
(4, 0, 0)
(3, 1, 0)
(2, 2, 0)
(2, 1, 1)
So, how to implement this? It looks like: while subtracting 1 from position i and adding it to the next position maintains our order, subtract 1 from position i, add 1 to position i + 1, and move to the next position. If we're in the last position, step back.
Here's a little python which does just that:
def partition_helper(l, i, result):
if i == len(l) - 1:
return
while l[i] - 1 >= l[i + 1] + 1:
l[i] -= 1
l[i + 1] += 1
result.append(list(l))
partition_helper(l, i + 1, result)
def partition(n, k):
l = [n] + [0] * (k - 1)
result = [list(l)]
partition_helper(l, 0, result)
return result
Now you have a list of lists (really a list of multisets), and generating all permutations of each multiset of the list gives you your solution. I won't go into that, there's a recursive algorithm which basically says, for each position, choose each unique element in the multiset and append the permutations of the multiset resulting from removing that element from the multiset.
Given that you ask this out of interest, you would probably be interested an authorative answer! It can be found in "7.2.1.2 - Generating all permutations" of Knuth's The Art of Computer Programming (subvolume 4A).
Also, 3 concrete algorithms can be found here.
As noted by #pbarranis, the code by #rlibby does not include all lists when n equals k. Below is Python code which does include all lists. This code is non-recursive, which may be more efficient with respect to memory usage.
def successor(n, l):
idx = [j for j in range(len(l)) if l[j] < l[0]-1]
if not idx:
return False
i = idx[0]
l[1:i+1] = [l[i]+1]*(len(l[1:i+1]))
l[0] = n - sum(l[1:])
return True
def partitions(n, k):
l = [0]*k
l[0] = n
results = []
results.append(list(l))
while successor(n, l):
results.append(list(l))
return results
The lists are created in colexicographic order (algorithm and more description here).
I found that using a recursive function was not good for larger lengths and integers because it chews up too much RAM, and using a generator / resumable-function (that 'yields' values) was too slow and required a large library to make it cross-platform.
So here's a non-recursive solution in C++ that produces the partitions in sorted order (which is ideal for permutations too). I've found this to be over 10 times faster than seemingly clever and concise recursive solutions I tried for partition lengths of 4 or greater, but for lengths of 1-3 the performance is not necessarily better (and I don't care about short lengths because they're fast with either approach).
// Inputs
unsigned short myInt = 10;
unsigned short len = 3;
// Partition variables.
vector<unsigned short> partition(len);
unsigned short last = len - 1;
unsigned short penult = last - 1;
short cur = penult; // Can dip into negative value when len is 1 or 2. Can be changed to unsigned if len is always >=3.
unsigned short sum = 0;
// Prefill partition with 0.
fill(partition.begin(), partition.end(), 0);
do {
// Calculate remainder.
partition[last] = max(0, myInt - sum); // Would only need "myInt - sum" if partition vector contains signed ints.
/*
*
* DO SOMETHING WITH "partition" HERE.
*
*/
if (partition[cur + 1] <= partition[cur] + 1) {
do {
cur--;
} while (
cur > 0 &&
accumulate(partition.cbegin(), partition.cbegin() + cur, 0) + (len - cur) * (partition[cur] + 1) > myInt
);
// Escape if seeked behind too far.
// I think this if-statement is only useful when len is 1 or 2, can probably be removed if len is always >=3.
if (cur < 0) {
break;
}
// Increment the new cur position.
sum++;
partition[cur]++;
// The value in each position must be at least as large as the
// value in the previous position.
for (unsigned short i = cur + 1; i < last; ++i) {
sum = sum - partition[i] + partition[i - 1];
partition[i] = partition[i - 1];
}
// Reset cur for next time.
cur = penult;
}
else {
sum++;
partition[penult]++;
}
} while (myInt - sum >= partition[penult]);
Where I've written DO SOMETHING WITH "partition" HERE. is where you would actually consume the value. (On the last iteration the code will continue to execute the remainder of the loop but I found this to be better than constantly checking for exit conditions - it's optimised for larger operations)
0,0,10
0,1,9
0,2,8
0,3,7
0,4,6
0,5,5
1,1,8
1,2,7
1,3,6
1,4,5
2,2,6
2,3,5
2,4,4
3,3,4
Oh I've used "unsigned short" because I know my length and integer won't exceed certain limits, change that if it's not suitable for you :) Check the comments; one variable there (cur) had to be signed to handle lengths of 1 or 2 and there's a corresponding if-statement that goes with that, and I've also noted in a comment that if your partition vector has signed ints there is another line that can be simplified.
To get all the compositions, in C++ I would use this simple permutation strategy which thankfully does not produce any duplicates:
do {
// Your code goes here.
} while (next_permutation(partition.begin(), partition.end()));
Nest that in the DO SOMETHING WITH "partition" HERE spot, and you're good to go.
An alternative to finding the compositions (based on the Java code here https://www.nayuki.io/page/next-lexicographical-permutation-algorithm) is as follows. I've found this to perform better than next_permutation().
// Process lexicographic permutations of partition (compositions).
composition = partition;
do {
// Your code goes here.
// Find longest non-increasing suffix
i = last;
while (i > 0 && composition[i - 1] >= composition[i]) {
--i;
}
// Now i is the head index of the suffix
// Are we at the last permutation already?
if (i <= 0) {
break;
}
// Let array[i - 1] be the pivot
// Find rightmost element that exceeds the pivot
j = last;
while (composition[j] <= composition[i - 1])
--j;
// Now the value array[j] will become the new pivot
// Assertion: j >= i
// Swap the pivot with j
temp = composition[i - 1];
composition[i - 1] = composition[j];
composition[j] = temp;
// Reverse the suffix
j = last;
while (i < j) {
temp = composition[i];
composition[i] = composition[j];
composition[j] = temp;
++i;
--j;
}
} while (true);
You'll notice some undeclared variables there, just declare them earlier in the code before all your do-loops: i, j, pos, and temp (unsigned shorts), and composition (same type and length as partition). You can reuse the declaration of i for it's use in a for-loop in the partitions code snippet. Also note variables like last being used which assume this code is nested within the partitions code given earlier.
Again "Your code goes here" is where you consume the composition for your own purposes.
For reference here are my headers.
#include <vector> // for std::vector
#include <numeric> // for std::accumulate
#include <algorithm> // for std::next_permutation and std::max
using namespace std;
Despite the massive increase in speed using these approaches, for any sizeable integers and partition lengths this will still make you mad at your CPU :)
Like I mentioned above, I couldn't get #rlibby's code to work for my needs, and I needed code where n=l, so just a subset of your need. Here's my code below, in C#. I know it's not perfectly an answer to the question above, but I believe you'd only have to modify the first method to make it work for different values of l; basically add the same code #rlibby did, making the array of length l instead of length n.
public static List<int[]> GetPartitionPermutations(int n)
{
int[] l = new int[n];
var results = new List<int[]>();
GeneratePermutations(l, n, n, 0, results);
return results;
}
private static void GeneratePermutations(int[] l, int n, int nMax, int i, List<int[]> results)
{
if (n == 0)
{
for (; i < l.Length; ++i)
{
l[i] = 0;
}
results.Add(l.ToArray());
return;
}
for (int cnt = Math.Min(nMax, n); cnt > 0; --cnt)
{
l[i] = cnt;
GeneratePermutations(l, (n - cnt), cnt, i + 1, results);
}
}
A lot of searching led to this question. Here is an answer that includes the permutations:
#!/usr/bin/python
from itertools import combinations_with_replacement as cr
def all_partitions(n, k):
"""
Return all possible combinations that add up to n
i.e. divide n objects in k DISTINCT boxes in all possible ways
"""
all_part = []
for div in cr(range(n+1), k-1):
counts = [div[0]]
for i in range(1, k-1):
counts.append(div[i] - div[i-1])
counts.append(n-div[-1])
all_part.append(counts)
return all_part
For instance, all_part(4, 3) as asked by OP gives:
[[0, 0, 4],
[0, 1, 3],
[0, 2, 2],
[0, 3, 1],
[0, 4, 0],
[1, 0, 3],
[1, 1, 2],
[1, 2, 1],
[1, 3, 0],
[2, 0, 2],
[2, 1, 1],
[2, 2, 0],
[3, 0, 1],
[3, 1, 0],
[4, 0, 0]]

Resources