Proportional representation and ratios - arrays

I need to generate a list of numbers to put into an array. These number of times that they occur in the list is based on how important a certain property is.
E.g.
// importance ranges from 0 (no importance) to 5 (utmost importance)
maxNumbersInArray = 10;
propAImportance = 5; --> will put 1 into the array
propBImportance = 3; --> will put 2 into the array
propCImportance = 2; --> will put 3 into the array
// Output will be
array = [1,1,1,1,1,2,2,2,3,3]
How can i create a list where the importance of a value means that value is added to an array a greater number of times, or more specifically, how to calculate how ofter a value will be added into an array based on a properties importance
First ideas: (language SQF scripting)
_max = 10;
_weight1 = 3;
_weight2 = 2;
_weight3 = 0;
_weight4 = 1;
_weights = [_weight1,_weight2,_weight3,_weight4];
_arr = [];
for "_i" from 0 to (_max - 1) do {
{
while {_i <= _x} do {
_arr set [(count _arr),_forEachIndex];
} forEach _weights;
};
_arr; // Output

I believe that this is the algorithm to use:
_index = [];
_max = 10;
_weights = [5,2,1,1];
_count = 0;
_countWeight = 0;
while {(count _index ) < _max } do {
if (_count >= (count _weights)) then {_count = 0};
_weight = _weights select _count;
_countWeight = _countWeight + 1;
if (_countWeight > _weight) then {
_countWeight = 0;
_count = _count + 1;
} else {
_index set [(count _index ),_count];
};
};

Related

Dividing elements in arrays on specific numbers

I have N arrays like this (4 in example but number can be different)
k1 = [1,0,0,0,1,0,1]
k2 = [0,1,1,0,1,0,1]
k3 = [1,0,0,0,1,0,0]
k4 = [0,0,0,0,1,1,1]
I need to get the following arrays:
k1 = [0.5,0,0,0,0.25,0,0.33]
k2 = [0, 1,1,0,0.25,0,0.33]
k3 = [0.5,0,0,0,0.25,0,0]
k4 = [0, 0,0,0,0.25,1,0.33]
The idea is to divide each element on number of "1" occurrences for the same index in other arrays. So you always get 1 as sum of k1[i]+k2[i]+k3[i]+k4[i]+...kn[i]
You have to create a new array with the sum of all elements and then divide like this :
there must be a "cleaner" way to do this but this works :
$k1 = [1,0,0,0,1,0,1];
$k2 = [0,1,1,0,1,0,1];
$k3 = [1,0,0,0,1,0,0];
$k4 = [0,0,0,0,1,1,1];
//we create an array with names of n array, i took 4 just to test it but it will works with n
$name=[];
for ($v = 1; $v <= 4; $v++) {
$name[$v]="k".$v;
}
$sum=[0,0,0,0,0,0,0];
for ($k = 0; $k <= 6; $k++) {
for ($j = 1; $j <= 4; $j++) {
$sum[$k]=$sum[$k]+${$name[$j]}[$k];
}
}
//and now we update
for ($l = 0; $l <= 6; $l++) {
if($sum[$l]!==0){
for ($q = 1; $q <= 4; $q++) {
${$name[$q]}[$l]=${$name[$q]}[$l]/$sum[$l];
}
}
}
//display to test
for ($m = 0; $m <= 6; $m++) {
echo $k1[$m];
echo " | ";
}

generating random numbers without repeating with an exception AS3

I have seen this question for other languages but not for AS3... and I'm having a hard time understanding it...
I need to generate 3 numbers, randomly, from 0 to 2, but they cannot repeat (as in 000, 001, 222, 212 etc) and they cannot be in the correct order (0,1,2)...
Im using
for (var u: int = 0; u < 3; u++)
{
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (u % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(u / 3));
mcCor.gotoAndStop((Math.random() * (2 - u + 1) + u) | 0); // random w/ repeats
//mcCor.gotoAndStop(Math.floor(Math.random() * (2 - u + 1) + u)); // random w/ repeats
//mcCor.gotoAndStop((Math.random() * 3) | 0); // crap....
//mcCor.gotoAndStop(Math.round(Math.random()*u)); // 1,1,1
//mcCor.gotoAndStop(u + 1); // 1,2,3
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
those are the codes i've been trying.... best one so far is the active one (without the //), but it still gives me duplicates (as 1,1,1) and still has a small chance to come 0,1,2....
BTW, what I want is to mcCor to gotoAndStop on frames 1, 2 or 3....without repeating, so THE USER can put it on the right order (1,2,3 or (u= 0,1,2), thats why I add + 1 sometimes there)
any thoughts?? =)
I've found that one way to ensure random, unique numbers is to store the possible numbers in an array, and then sort them using a "random" sort:
// store the numbers 0, 1, 2 in an array
var sortedNumbers:Array = [];
for(var i:int = 0; i < 3; i++)
{
sortedNumbers.push(i);
}
var unsortedNumbers:Array = sortedNumbers.slice(); // make a copy of the sorted numbers
trace(sortedNumbers); // 0,1,2
trace(unsortedNumbers); // 0,1,2
// randomly sort array until it no longer matches the sorted array
while(sortedNumbers.join() == unsortedNumbers.join())
{
unsortedNumbers.sort(function (a:int, b:int):int { return Math.random() > .5 ? -1 : 1; });
}
trace(unsortedNumbers); // [1,0,2], [2,1,0], [0,1,2], etc
for (var u: int = 0; u < 3; u++)
{
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (u % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(u / 3));
// grab the corresponding value from the unsorted array
mcCor.gotoAndStop(unsortedNumbers[u] + 1);
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
Marcela is right. Approach with an Array is widely used for such task. Of course, you will need to check 0, 1, 2 sequence and this will be ugly, but in common code to get the random sequence of integers can look like this:
function getRandomSequence(min:int, max:int):Array
{
if (min > max) throw new Error("Max value should be greater than Min value!");
if (min == max) return [min];
var values:Array = [];
for (var i:int = min; i <= max; i++) values.push(i);
var result:Array = [];
while (values.length > 0) result = result.concat(values.splice(Math.floor(Math.random() * values.length), 1));
return result;
}
for (var i:uint = 0; i < 10; i++)
{
trace(getRandomSequence(1, 10));
}
You will get something like that:
2,9,3,8,10,6,5,1,4,7
6,1,2,4,8,9,5,10,7,3
3,9,10,6,8,2,5,4,1,7
7,6,1,4,3,8,9,2,10,5
4,6,7,1,3,2,9,10,8,5
3,10,5,9,1,7,2,4,8,6
1,7,9,6,10,3,4,5,2,8
4,10,8,9,3,2,6,1,7,5
1,7,8,9,10,6,4,3,2,5
7,5,4,2,8,6,10,3,9,1
I created this for you. It is working but it can be optimized...
Hope is good for you.
var arr : Array = [];
var r : int;
for (var i: int = 0; i < 3; i++){
r=rand(0,2);
if(i == 1){
if(arr[0] == r){
i--;
continue;
}
if(arr[0] == 0){
if(r==1){
i--;
continue;
}
}
}else if(i==2){
if(arr[0] == r || arr[1] == r){
i--;
continue;
}
}
arr[i] = r;
}
trace(arr);
for(var i=0;i<3;i++){
mcCor = new CorDaCarta();
mcCor.x = larguraTrio + (mcCor.width + 5) * (i % 3);
mcCor.y = alturaTrio + (mcCor.height + 5) * (Math.floor(i / 3));
mcCor.gotoAndStop(arr[i]);
mcCor.buttonMode = true;
mcCor.addEventListener(MouseEvent.CLICK, cliquetrio);
mcExplic.addChild(mcCor);
trio.push(mcCor);
}
function rand(min:int, max:int):int {
return Math.round(Math.random() * (max - min) + min);
}
try this...

Get longest continuous sequence of 1s

I recently encountered a problem statement it says:
Given an array of 0s and 1s, find the position of 0 to be
replaced with 1 to get longest continuous sequence of 1s.
For example : Array- 1,1,0,0,1,0,1,1,1,0,1,1,1
Output - index 9
I tried a brute force approach replacing every encountered 0 with 1 and after each such replacement, i counted the largest continuous repetitive sequence of 1 and updated it every time.
Is there a better approach/algorithm to this problem?
There should be a one-pass solution to this. The overall idea is to count the ones and to add up the lengths for each zero as you go. Well, not each zero, just the last encountered one and the longest.
You need to keep track of two things:
The longest chain so far.
The previous zero value, along with the length of the preceding ones.
The process then goes as following:
Starting walking through the string until you encounter a zero. Keep track of the number of ones as you go.
When you hit the zero, remember the position of the zero along with the number of preceding 1s.
Count the 1s to the next zero.
Go back to the previous zero and add the new "ones" to the previous "ones". If this is longer than the longest chain, then replace the longest chain.
Remember this zero along with the preceding 1s.
Repeat until you have reached the end of the string.
At then end of the string, go back and add the length to the previous zero and replace the longest chain if appropriate.
You can imagine you have to maintain a set of 1 allowing only one 0 among them,
so
1) walk over the array,
2) if you are getting a 1,
check a flag if you are already in a set, if no,
then you start one and keep track of the start,
else if yes, you just update the end point of set
3) if you get a 0, then check if it can be included in the set,
(i.e. if only one 0 surrounded by 1 "lonely zero" )
if no, reset that flag which tells you you are in a set
else
is this first time ? (store this 0 pos, initialized to -1)
yes, then just update the zero position
else okk, then previous set, of one..zero..one gets finished here,
now the new set's first half i.e. first consecutive ones are the previous set's last portion,
so set the beginning of the set marker to last zero pos +1, update the zero position.
So when to get check if the current set is having highest length? See , we update the end point only in 2 -> else portion, so just check with max start, max end etc etc at that point and it should be enough
Here is my solution. It is clean, takes O(n) time and O(1) memory.
public class Q1 {
public Q1() {
}
public static void doit(int[] data) {
int state = 0;
int left, right, max_seq, max_i, last_zero;
left = right = 0;
max_seq = -1;
max_i = -1;
// initialization
right = data[0];
last_zero = (data[0]==0) ? 0 : -1;
for (int i = 1; i < data.length; i++) {
state = data[i - 1] * 10 + data[i];
switch (state) {
case 00: //reset run
left = right = 0;
last_zero = i;
break;
case 01: // beginning of a run
right++;
break;
case 10:// ending of a run
if(left+right+1>max_seq){
max_seq = left+right+1;
max_i = last_zero;
}
last_zero = i; //saving zero position
left = right; // assigning left
right = 0; // resetting right
break;
case 11: // always good
right++;
break;
}
}
//wrapping up
if(left+right+1>max_seq){
max_seq = left+right+1;
max_i = last_zero;
}
System.out.println("seq:" + max_seq + " index:" + max_i);
}
public static void main(String[] args) {
//Q1.doit(new int[] { 1,1,0,0,1,0,1,1,1,0,1,1,1 });
Q1.doit(new int[] { 1,1,0,0,1,0,1,1,1,0,1,1,1 });
}
}
Using Dynamic programming you can solve this code.
Time complexity is O(n) and space complexity is O(n).
public static int Flipindex(String mystring){
String[] arr = mystring.split(",");
String [] arrays= new String[arr.length];
for(int i=0;i<arr.length;i++){
arrays[i]="1";
}
int lastsum = 0;
int[] sumarray =new int[arr.length];
for(int i=0;i<arr.length;i++){
if(!arr[i].equals(arrays[i])){
++lastsum;
}
sumarray[i]=lastsum;
}
int [] consecsum = new int [sumarray[sumarray.length-1]+1];
for(int i: sumarray){
consecsum[i]+=1;
}
int maxconsecsum=0,startindex=0;
for(int i=0;i<consecsum.length-1;i++){
if((consecsum[i]+consecsum[i+1])>maxconsecsum){
maxconsecsum=(consecsum[i]+consecsum[i+1]);
startindex=i;
}
}
int flipindex=0;
for(int i=0;i<=startindex;i++){
flipindex+=consecsum[i];
}
return flipindex;
}
public static void main(String[] args) {
String s= "1,1,0,0,1,0,1,1,1,0,1,1,1";
System.out.println(Flipindex(s));
}
Playing around with console yielded me this, touch up and cover edge case then you are good to go
function getIndices(arr, val) {
var indexes = [], i = -1;
while ((i = arr.indexOf(val, i+1)) != -1){
indexes.push(i);
}
return indexes;
}
var a = [1,1,1,1,1,0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,0];
var z = getIndices(a, 0);
z.unshift(0);
var longestchain = 0;
var target = 0;
for(var i=0;i<z.length;i++) {
if(i == 0) { //first element
longestchain = z[i] + z[i+1];
target = i;
} else if (i == z.length-1) { //last element
var lastDistance = Math.abs(z[i] - z[i-1]);
if(lastDistance > longestchain) {
longestchain = lastDistance;
target = i;
}
} else {
if(Math.abs(z[i] - z[i+1]) > 1) { //consecutive 0s
//look before and ahead
var distance = Math.abs(z[i-1] - z[i]) + Math.abs(z[i] - z[i+1]);
if(distance > longestchain) {
longestchain = distance;
target = i;
}
}
}
}
console.log("change this: " + z[target]);
I first search for zeroes in the array and stored the position in another array, so in my e.g. you will get something like this [0,5,6,8,9,13,20], then i just run a single loop to find the greatest distance from each element with their adjacent ones, and storing the distance in the "longestchain", everytime i find a longer chain, i take note of the index, in this case "13".
This C code implementation is based on the algorithm provided by #gordon-linoff above.
int maxOnesIndex1(bool arr[], int n)
{
int prevZeroPos = 0;
int oldOneCnt = 0;
int newOneCnt = 0;
int longestChainOfOnes = 0;
int longestChainPos = 0;
int i;
for(i=0; i<n; i++)
{
if(arr[i]!=0)
{
oldOneCnt++;
}
else // arr[i] == 0
{
prevZeroPos = i;
newOneCnt = 0;
// move by one to find next sequence of 1's
i++;
while(i<n && arr[i] == 1)
{
i++;
newOneCnt++;
}
if((oldOneCnt+newOneCnt) > longestChainOfOnes)
{
longestChainOfOnes = oldOneCnt+newOneCnt+1;
longestChainPos = prevZeroPos;
}
oldOneCnt = 0;
i = prevZeroPos;
}
}
if((oldOneCnt+newOneCnt) > longestChainOfOnes)
{
longestChainOfOnes = oldOneCnt+newOneCnt+1;
longestChainPos = prevZeroPos;
}
return longestChainPos;
}
Space Complexity - O(1)
Time Complexity - O(n)
A = map(int, raw_input().strip().split(' '))
left = 0 #Numbers of 1 on left of current index.
right = 0 #Number of 1 on right of current index.
longest = 0 #Longest sequence so far
index = 0
final_index = 0 # index of zero to get the longest sequence
i = 0
while i < A.__len__():
if A[i] == 0:
left = right
index = i
i += 1
right = 0
while i < A.__len__() and A[i] != 0:
right += 1
i += 1
if left + right + 1 > longest:
final_index = index
longest = left + right + 1
else:
right += 1
i += 1
print final_index, longest
Here is little different algorithm
public static int zeroIndexToGetMaxOnes(int[] binArray) {
int prevPrevIndex = -1, prevIndex = -1,currentLenght= -1, maxLenght = -1, requiredIndex = -1;
for (int currentIndex = 0; currentIndex < binArray.length; currentIndex++) {
if (binArray[currentIndex] == 0) {
if (prevPrevIndex != -1) {
currentLenght = currentIndex - (prevPrevIndex + 1);
if (currentLenght > maxLenght) {
maxLenght = currentLenght;
requiredIndex = prevIndex;
}
}
prevPrevIndex = prevIndex;
prevIndex = currentIndex;
} else {// case when last element is not zero, and input contains more than 3 zeros
if (prevIndex != -1 && prevPrevIndex != -1) {
currentLenght = currentIndex - (prevPrevIndex + 1);
if (currentLenght > maxLenght) {
maxLenght = currentLenght;
requiredIndex = prevIndex;
}
}
}
}
if (maxLenght == -1) { // less than three zeros
if (prevPrevIndex != -1) { // 2 zeros
if (prevIndex > (binArray.length - prevPrevIndex - 1)) {
requiredIndex = prevPrevIndex;
} else {
requiredIndex = prevIndex;
}
} else { // one zero
requiredIndex = prevIndex;
}
}
return requiredIndex;
}
Here is the unit tests
#Test
public void replace0ToGetMaxOnesTest() {
int[] binArray = {1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1};
int index = ArrayUtils.zeroIndexToGetMaxOnes(binArray);
assertThat(index, is(9));
binArray = new int[]{1,0,1,1,1,0};
index = ArrayUtils.zeroIndexToGetMaxOnes(binArray);
assertThat(index, is(1));
binArray = new int[]{0,1,1,1,0,1};
index = ArrayUtils.zeroIndexToGetMaxOnes(binArray);
assertThat(index, is(4));
binArray = new int[]{1,1,1,0,1,0};
index = ArrayUtils.zeroIndexToGetMaxOnes(binArray);
assertThat(index, is(3));
binArray = new int[]{0,1,1,1,0};
index = ArrayUtils.zeroIndexToGetMaxOnes(binArray);
assertThat(index, is(4));
binArray = new int[]{1,1,1,1,0};
index = ArrayUtils.zeroIndexToGetMaxOnes(binArray);
assertThat(index, is(4));
binArray = new int[]{0,1,1,1,1};
index = ArrayUtils.zeroIndexToGetMaxOnes(binArray);
assertThat(index, is(0));
}
def sol(arr):
zeros = [idx for idx, val in enumerate(arr) if val == 0]
if len(arr) == 0 or len(zeros) == 0:
return None
if len(arr) - 1 > zeros[-1]:
zeros.append(len(arr))
if len(zeros) == 1:
return zeros[0]
if len(zeros) == 2:
return max(zeros)
max_idx = None
diff = 0
for i in range(len(zeros) - 2):
# Calculating the difference of i+2 and i, since i+1 should be filled with 1 to find the max index
if zeros[i+2] - zeros[i] > diff:
diff = zeros[i + 2] - zeros[i] - 1
max_idx = zeros[i+1]
return max_idx
arr = [1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1]
print(sol(arr))

Get evenly spaced X, Y cords from a given size and required amount

I'm working in Actionscript 3, but this is pretty general.
I'd like to make a simple function that I can call, e.g. GiveCords(Width, Height, Num) that will take a width and height, map that out and using the Num variable place the given amount evenly across the space.
Say I give it a value of 500, 500, 1. I'd expect it to return an X, Y position of 250, 250.
But I'd like it to return an array of given points with X, Y.
So If I gave it 10 points, it would find the best position for them all to be of even distance apart from each other.
I'm guessing there is a simple formula for working this out, but I've searched a plenty and found nothing.
Cheers
If I understood correctly this should do the job:
var object:Object = {width: 500, height:500, num:10};
var points:Array = getCoordinates(object);
function getCoordinates(object:Object):Array {
var array:Array = new Array();
var widthMultiplier:Number = object.width / (object.num + 1);
var heightMultiplier:Number = object.height / (object.num + 1);
for (a = 1; a <= object.num; a++) {
var coordinates:Point = new Point();
coordinates.x = widthMultiplier * a;
coordinates.y = heightMultipler * a;
array.push(coordinates);
}
return array;
}
It takes the number of items and the total space, divides the total space by the number of items + 1 (to account for the space at the end of the last element) increment the objects each time.
Edit: In response to comments here is a version where you can state the number of rows you want your objects to spread across. If the number of rows does not divide the number of objects and return an integer then the function will return null. If you do not give it a rows paramater it assumes you want it across one row. Enjoy.
var object:Object = {width:500,height:500,num:10};
var points:Array = getCoordinates(object,2);
function getCoordinates(object:Object, rows:int = 1):Array
{
if ((object.num / rows) % 1)
{
return null;
}
else
{
var columns:int = object.num / rows;
var array:Array = new Array();
var widthMultiplier:Number = object.width / (columns + 1);
var heightMultiplier:Number = object.height / (rows + 1);
for (var a = 1; a <= rows; a++)
{
for (var b = 1; b <= columns; b++)
{
var coordinates:Point = new Point();
coordinates.x = widthMultiplier * b;
coordinates.y = heightMultiplier * a;
array.push(coordinates);
}
}
return array;
}
}

skyline algorithm

How do I find the vertices of the broken line that surrounds the silhouette in this image?
A possible input for the example above is:
WIDTH HEIGHT POSITION
3 9 17
5 9 9
12 4 8
3 11 3
10 7 1
2 3 19
So for this example the solution would be
[(1, 0), (1, 7), (3, 7), (3, 11), (6, 11), (6, 7),
(9, 7), (9, 9), (14, 9), (14, 4), (17, 4), (17, 9),
(20, 9), (20, 3), (21, 3), (21, 0)]
This is pretty simple. Make an array that is the length of the X axis, initialize to 0. As you read in the inputs, write the heights into this array if the height is >= the current value at that location in the array.
Then just loop over the array, and every time the value changes it is a vertex.
Basically:
int heights[SIZE] = {0};
int i, width, pos, height, prev = -1;
while (scanf("%d %d %d", &width, &height, &pos) == 3) {
for (i = 0; i < width; ++i) {
if (heights[pos+i] < height)
heights[pos+i] = height;
}
}
for (i = 0; i < SIZE; ++i) {
if (heights[i] != prev) {
printf("(%d,%d) ", i+1, heights[i]);
prev = heights[i];
}
}
printf("\n");
In the naive case, this doesn't seem like a very difficult algorithm. Do you know if the input size will get large/how large?
My initial attempt: Try to move from left to right. First pick the block with the leftmost edge that exists on the origin line. Climb to its top. Find all blocks with a left edge between the current point and the upper right point of the current block. Of that set, pick the closest (but check for edge cases, pun not intended). If the set is empty, start working your way down the right side of the block, looking for other blocks you may intercept.
Basically this is just how you'd trace it with your eye.
You can do some simple optimization by keeping sorted lists and then searching the lists rather than finding sets and digging around. For example, you might keep 4 sorted lists of the blocks, each sorted by the x or y coordinate of one of the sides.
If you have many, many blocks, you could consider using a multi-dimensional data structure to further organize the information.
I solved this problem using the sweep-line algorithm. This is a python class solution.
there two keys:
1) using the variable "points" to save all the left and right points and their heights and the sign of the height to indicate whether the points are left or right.
2) the variable "active" is used to save all the active lines that has been scanned.
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]]] # the negative sign means this point is a right point
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]) #remove height of the lines than have been finished with scanning
i+=1
else:
break
if max(active)<current:
current=max(active)
res+=[[points[moving][0], current]]
moving=i
return res
I made a Java class to try and solve this. The class includes methods for generating, solving and printing data-sets. I haven't tested extensively, there may be a few bugs remaining. Also, my solution may be needlessly complicated, but it's designed to work (in theory) for non-discrete height and coordinate values.
import java.util.Random;
public class Skyline {
private int[][] buildings;
private int[][] skyline;
private int maxLength;
private int maxHeight;
public Skyline(int buildings, int maxLength, int maxHeight) {
this.maxLength = maxLength;
this.maxHeight = maxHeight;
makeRandom(buildings);
}
public Skyline(int[][] buildings, int dimensions) {
this.maxLength = maxLength;
this.maxHeight = maxHeight;
this.buildings = buildings;
}
public void makeRandom(int buildings) {
this.buildings = new int[buildings][3];
Random rand = new Random();
for(int i = 0; i < buildings; i++) {
int start = rand.nextInt(maxLength-3);
int end = rand.nextInt(maxLength - start - 1) + start + 1;
int height = rand.nextInt(maxHeight-1) + 1;
this.buildings[i][0] = start;
this.buildings[i][1] = height;
this.buildings[i][2] = end;
}
boolean swapped = true;
while(swapped) {
swapped = false;
for(int i = 0; i < this.buildings.length-1; i++) {
if(this.buildings[i][0] > this.buildings[i+1][0]) {
swapped = true;
int[] temp = this.buildings[i];
this.buildings[i] = this.buildings[i+1];
this.buildings[i+1] = temp;
}
}
}
// this.buildings[0][0] = 2;
// this.buildings[0][1] = 3;
// this.buildings[0][2] = 8;
}
public void printBuildings() {
print(this.buildings, false);
}
public void printSkyline() {
print(this.buildings, true);
}
public void print(int[][] buildings, boolean outline) {
char[][] str = new char[this.maxLength][this.maxHeight];
for(int i = 0; i < this.maxLength; i++) {
for(int j = 0; j < this.maxHeight; j++) {
str[i][j] = '.';
}
}
for(int i = 0; i < buildings.length; i++) {
int start = buildings[i][0];
int height = buildings[i][1];
int end = buildings[i][2];
//print the starting vertical
for(int j = 0; j < height; j++) {
if(outline) str[start][j] = str[start][j] == '|' ? '.' : '|';
else str[start][j] = '|';
}
//print the ending vertical
for(int j = 0; j < height; j++) {
if(outline) str[end][j] = str[end][j] == '|' ? '.' : '|';
else str[end][j] = '|';
}
//print the horizontal
if(height > 0) {
for(int j = start; j <= end; j++) {
str[j][height] = str[j][height] == '|' ? '|' : '-';
}
}
}
for(int i = maxHeight-1; i >= 0; i--) {
for(int j = 0; j < maxLength; j++) {
System.out.print(str[j][i]);
}
System.out.println();
}
System.out.println();
}
public void solveSkyline() {
for(int i = 0; i < buildings.length; i++) {
boolean reduced = true;
while(reduced) {
reduced = false;
for(int j = i+1; j < buildings.length; j++) {
if(buildings[j][0] < buildings[i][2] && buildings[j][1] > buildings[i][1] && buildings[j][2] >= buildings[i][2]) { //if intersecting building is taller, and longer
buildings[i][2] = buildings[j][0];
reduced = true;
break;
} else if(buildings[j][0] < buildings[i][2] && buildings[j][1] <= buildings[i][1] && buildings[j][2] >= buildings[i][2]) { //intersecting building is shorter, but longer
buildings[j][0] = buildings[i][2];
reduced = true;
break;
} else if(buildings[j][0] < buildings[i][2] && buildings[j][1] > 0 && buildings[j][1] < buildings[i][1] && buildings[j][2] <= buildings[i][2]) { //building is invisible, so ignore it
buildings[j][1] = 0;
reduced = true;
break;
} else if(buildings[j][0] < buildings[i][2] && buildings[j][2] <= buildings[i][2] && buildings[j][1] > buildings[i][1]) {
int[] newBuilding = new int[]{buildings[j][2], buildings[i][1], buildings[i][2]};
int[][] newBuildings = new int[buildings.length+1][3];
boolean inserted = false;
buildings[i][2] = buildings[j][0];
for(int k = 0; k < buildings.length; k++) {
if(inserted == false) {
if(newBuilding[0] < buildings[k][0]) {
newBuildings[k] = newBuilding;
newBuildings[k+1] = buildings[k];
inserted = true;
} else {
newBuildings[k] = buildings[k];
}
}
if(inserted == false && k == buildings.length - 1) {
newBuildings[k+1] = newBuilding;
} else {
newBuildings[k+1] = buildings[k];
}
}
buildings = newBuildings;
reduced = true;
break;
}
}
}
}
}
public static void main(String args[]) {
Skyline s = new Skyline(5, 100, 10);
s.printBuildings();
s.solveSkyline();
s.printBuildings();
s.printSkyline();
}
}
My solution to the problem as described here https://leetcode.com/problems/the-skyline-problem/ it iterates the list of buildings twice, however this could be combined into a single iteration. However, there are more optimal approaches if you consider the pure algorithm solution explained here http://www.algorithmist.com/index.php/UVa_105
class Solution {
public:
vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
// The final result.
vector<pair<int, int>> result;
// To hold information about the buildings
std::set<BuildingInformation> buildingInformation;
// Go through each building, and store information about the start and end heights.
for ( vector<vector<int>>::iterator buildingIt = buildings.begin( ); buildingIt != buildings.end( ); ++buildingIt ) {
BuildingInformation buildingStart;
buildingStart.x = (*buildingIt)[0];
buildingStart.h = (*buildingIt)[2];
buildingStart.StartOrEnd = Start;
buildingInformation.insert(buildingStart);
buildingStart.x = (*buildingIt)[1];
buildingStart.StartOrEnd = End;
buildingInformation.insert(buildingStart);
}
// Keep track of the current height.
int currentHeight = 0;
// A map of active building heights against number of buildings (to handle multiple buildings overlapping with same height).
// As it is a map, it'll be sorted by key, which is the height.
std::map<int, int> heights;
// Go through each building information that we generated earlier.
for ( std::set<BuildingInformation>::iterator it = buildingInformation.begin( ); it != buildingInformation.end( ); ++it ) {
if ( it->StartOrEnd == Start ) {
// This is a start point, do we have this height already in our map?
if ( heights.find( it->h ) != heights.end( ) ) {
// Yes, increment count of active buildings with this height/
heights[ it->h ] += 1;
} else {
// Nope, add this building to our map.
heights[ it->h ] = 1;
}
// Check if building height is taller than current height.
if ( it->h > currentHeight ) {
// Update current height and add marker to results.
currentHeight = it->h;
result.push_back( pair<int, int>( it->x, currentHeight ) );
}
} else {
// This is an end point, get iterator into our heights map.
std::map<int, int>::iterator heightIt = heights.find( it->h );
// Reduce by one.
heightIt->second -= 1;
// If this was the last building of the current height in the map...
if ( heightIt->second == 0 ) {
// Remove from heights map.
heights.erase( heightIt );
// If our height was the current height...
if ( it->h == currentHeight ) {
// If we have no more active buildings...
if ( heights.size( ) == 0 ) {
// Current height is zero.
currentHeight = 0;
} else {
// Otherwise, get iterator to one past last.
heightIt = heights.end( );
// Go back to get last valid iterator.
--heightIt;
// Store current height.
currentHeight = heightIt->first;
}
// Add marker to results.
result.push_back( pair<int, int>( it->x, currentHeight ) );
}
}
}
}
return result;
}
private:
// Is this a building start or end?
enum BuildingStartOrEnd
{
Start = 0,
End
};
// Information about building, there are two of these for each building, one for start, one for end.
struct BuildingInformation
{
int x;
int h;
BuildingStartOrEnd StartOrEnd;
// The ordering algorithm for the key, the rules we want to implement is keys are put in X order, and
// in the case of a tie (x values the same), we want Start pieces to come before End pieces (this is
// to handle cases where an old building ends and a new building begins on same X index, in which case
// we want to process the new start before processing the old end), however if we have two Start pieces
// at the same index, we wish to favour taller pieces (in this scenario we want to add a marker for the
// tallest building), finally if we have two End pieces at the same index, we wish to prefer lower
// pieces, as when multiple buildings end, we only want to add one result for the ultimate lowest point.
bool operator < ( const BuildingInformation & rhs ) const
{
if ( x == rhs.x )
{
if ( StartOrEnd == rhs.StartOrEnd ) {
if ( StartOrEnd == Start )
return h > rhs.h;
else
return h < rhs.h;
} else {
return StartOrEnd < rhs.StartOrEnd;
}
}
return x < rhs.x;
}
};
};

Resources