StoneWall – Codility – Solution

Java solution to Codility StoneWall problem (Lesson 7 – Stacks and Queues) which scored 100%. The problem is to build a “Manhattan skyline” using the minimum number of rectangle blocks.

The strategy is:

  • break up each array element into sub-blocks to store on a stack
  • for each subsequent array element, check if there are existing blocks on the stack that can create it
  • only add new block to the stack if impossible to reuse sub-blocks from stack

Example

{ 8, 8, 5, 7, 9, 8, 7, 4, 8 } will be broken down into the following 7 unique blocks:

(0,8) //8
(0,8) //8
(0,5) //5 (after clearing stack)
(0,5), (5,7) //7
(0,5), (5,7), (7,9) //9
(0,5), (5,7), (7,8) //8 (after popping stack)
(0,5), (5,7) //7 (after popping stack)
(0,4) // 4 (after clearing stack)
(0,4), (4,8) //8

[cc lang="java" escaped="true"]
package com.codility.lesson07.stacksqueues;

import java.util.Stack;

public class StoneWall {
	public int solution(int[] H) {

		//e.g. H[0] = 2 would be a block of size (0, 2)
		Block currentBlock = new Block(0, H[0]);
		Stack blockStack = new Stack();
		
		blockStack.add(currentBlock);
		int blocksRequired = 1;

		for(int i=1; i<H.length; i++) { Block topStackBlock = blockStack.peek(); //remove any stack blocks that are taller than current block while(topStackBlock.upperHeight > H[i] ) {
				blockStack.pop();
				if(!blockStack.isEmpty()) {
					topStackBlock = blockStack.peek();
				}
				else break;
			}
			
			if(blockStack.isEmpty()) {
				blockStack.push(new Block(0, H[i]));
				blocksRequired++;
			}
			//block already exists in stack
			else if(blockStack.peek().upperHeight - H[i] == 0) {
				continue;
			}
			//put in a new block - need to calculate delta between tallest stack block and current block
			else {
				topStackBlock = blockStack.peek();
				blockStack.push(new Block(blockStack.peek().upperHeight, H[i]));
				blocksRequired++;
			}
		}
		
		return blocksRequired;
	}
	
	class Block {
		int lowerHeight;
		int upperHeight;
		
		Block(int pLowerHeight, int pUpperHeight) {
			lowerHeight = pLowerHeight;
			upperHeight = pUpperHeight;
		}
	}
}
[/cc]

TestNG test cases for this problem which all passed:

[cc lang="java" escaped="true"]
package test.com.codility.lesson07.stacksqueues;

import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import com.codility.lesson07.stacksqueues.StoneWall;

public class StoneWallTests {
	private StoneWall solution;
	
	@BeforeTest
	public void setUp() {
		solution = new StoneWall();
	}

	@DataProvider(name = "test1")
	public Object [][] createData1() {
		return new Object [][] {
			new Object [] { new int [] { 8, 8, 5, 7, 9, 8, 7, 4, 8 }, 7 }, 
			new Object [] { new int [] { 8, 8, 5, 7, 9, 8, 7, 5, 8 }, 6 },
			new Object [] { new int [] { 1, 2, 3, 4, 3 }, 4 },
			new Object [] { new int [] { 8, 8, 5 }, 2 },
			new Object [] { new int [] { 8, }, 1 },
			new Object [] { new int [] { 8, 8 }, 1 },
			new Object [] { new int [] { 8, 8, 8, 8, 8 }, 1 },
			new Object [] { new int [] { 1000000000 }, 1 },
			new Object [] { new int [] { 1000000000, 2 }, 2 },
			new Object [] { new int [] { 2, 1000000000, 2 }, 2 },
			new Object [] { new int [] { 2, 1000000000, 2, 1000000000 }, 3 },
			new Object [] { new int [] { 2, 1000000000, 2, 1000000000, 1000000000 }, 3 },
		};
	}

	@Test(dataProvider = "test1")
	public void verifySolution(int[] pA, int pExpected) {		
		Assert.assertEquals(solution.solution(pA), pExpected);
	}	
}
[/cc]