Microsoft Interview Question for Software Engineer in Tests


Interview Type: Phone Interview




Comment hidden because of low score. Click to expand.
2
of 4 vote

First, consider the following problem (Maximizing Histogram rectangle area problem): Given an array of non-negative integers which represents column heights in a column graph, what is the maximum area rectangle in the given graph?
For instance, suppose array = {1,3,5,2,4,1,3} (first column height is 1, second is 3,...). The maximum area rectangle's height in this case is 2 and its width would be 4 (corresponding to the indices 1,2,3,4 in array).

To solve this problem we'll maintain a stack of array indices with the following constraints:
1. The indices are in increasing order.
2. The column heights which correspond to the stack indices are in a non-decreasing order.

We'll iterate over the array and we'll push indices into the stack as long as conditions (1) and (2) hold. If we've reached a point where we can't push an index without violating constraint (2) then that means that the height of the current column (column i) is smaller than the column whose index is at the top of the stack. In this case, we'll pop indices and compare rectangle areas (with the maximum area) until we can finally push the current index into the stack. The rectangle area at each stage (when we pop) will be calculated by multiplying the popped column height - height(popped_index) and the number of columns between him and the current column (the columns we already popped) - current_index - popped_index. Notice that constraint (1) implies that the column heights of columns between the column at the top of the stack and the current column are all greater/equal to the stack's top column height which implies that the area we calculate is indeed of a rectangle which is included in the column graph.

Here is an implementation of this idea (the method maxHistRect()):

private static class AreaIndices {
		public final int from;
		public final int to;
		public final int height;
		
		public AreaIndices(int from, int to, int height){
			this.from = from;
			this.to = to;
			this.height = height;
		}
		
		public int area(){return (to-from+1)*height;}
		
		@Override
		public String toString(){return "(" + from + "," + to + "," + height + ")";}
	}
	
	private static AreaIndices maxHistRect(int[] histogram){
		if (histogram==null){return null;}
		
		Stack<Integer> stack = new Stack<Integer>();
		AreaIndices res = new AreaIndices(0,0,0);
		int i=0;
		while ((i<histogram.length) || (!stack.isEmpty())){
			if ((stack.isEmpty()) || ((i<histogram.length) && (histogram[i]>=histogram[stack.peek()]))){stack.push(i++);}
			else {
				int cur = stack.pop();
				if (histogram[cur]*(i-cur) >= res.area()){res = new AreaIndices(cur,i-1,histogram[cur]);}
			}
		}
		
		return res;
	}

Now that we know the solution to the Maximum Histogram Rectangle problem, we'll solve the original problem. We'll build an mxn array (assuming the input matrix is mxn) - dp in the following way:
dp[i][j] = 0 if matrix[i][j] == 0
dp[i][j] = 1 + dp[i][j-1] if matrix[i][j] == 1 (I'll consider dp[i][-1] as 0)
The resulting matrix dp is a matrix where dp[i][j] represents the number of consecutive 1's (without 0 in between) in column j which end in row i (including). For instance, if dp[i][j] = 4 then it means that matrix[i][j-3] = matrix[i][j-2] = matrix[i][j-1] = matrix[i][j] = 1.

Here is the code that builds the matrix dp:

private static int[][] buildHistograms(int[][] arr){
		if (arr==null){return null;}
		for (int i=0;i<arr.length;i++){
			if ((arr[0]==null) || ((i>0) && (arr[i].length != arr[i-1].length))){return null;}
		}
		
		int m = arr.length,n = arr[0].length;
		int[][] dp = new int[m][n];
		for (int i=0;i<dp.length;i++){
			for (int j=0;j<dp[i].length;j++){
				dp[i][j] = (arr[i][j]==0) ? 0 : 1 + ((i>0) ? dp[i-1][j] : 0);
			}
		}
		
		return dp;
	}

After building the matrix dp, we can look at each row dp[i] in this matrix as a column graph (the height in this case is the number of consecutive 1's in each column ending in the row i). We already know how to find the maximum area rectangle in a column graph.

For instance, suppose we found that the maximum area rectangle for dp[i] has height of h and corresponds to columns k,k+1,...,l. By the definition of dp we conclude that our matrix has the following rectangle: start_row = i-h+1, end_row = i, start_column = k, end_column = l.

All that's left is to find the maximum rectangle for every row dp[i] and to take the maximum between all of them (getMaxOnesRectange()):

public static class RectangleCoordinates {
		public final int rowFrom;
		public final int rowTo;
		public final int colFrom;
		public final int colTo;
		
		public RectangleCoordinates(int rowFrom, int rowTo, int colFrom, int colTo){
			this.rowFrom = rowFrom;
			this.rowTo = rowTo;
			this.colFrom = colFrom;
			this.colTo = colTo;
		}
		
		@Override
		public String toString(){
			return "Rows: " + rowFrom + "-" + rowTo + ", Columns: " + colFrom + "-" + colTo;
		}
	}
	
	public static RectangleCoordinates getMaxOnesRectange(int[][] arr){
		if (arr==null){return null;}
		
		int[][] dp = buildHistograms(arr);
		if (dp==null){return null;}
		AreaIndices max = null;
		RectangleCoordinates res = null;
		
		for (int i=0;i<dp.length;i++){
			AreaIndices cur = maxHistRect(dp[i]);
			if ((max==null) || (max.area()<cur.area())){
				max = cur;
				res = new RectangleCoordinates(i-cur.height+1,i,cur.from,cur.to);
			}
		}
		
		return res;
	}

This solution is O(m*n) run-time and space. It also finds the maximum area rectangle consisting from 1's. It is easy to use it to find the maximum area rectangle consisting from 0's as well (just apply it to the matrix with all elements switched from 0 to 1 and from 1 to 0).

It worked for the couple of tests I ran but I didn't test it too thoroughly.

- IvgenyNovo January 13, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Great solution. There might be a small error though:
After popping an element from the stack in maxHistRect you calculate the max area as

histogram[cur]*(i-cur)

histogram[cur] is obviously the height, i the right border, and cur the left border of the rectangle. The left border can be more on the left side. In fact the left border is the index of the top element on the stack after popping, thus it should be:

histogram[cur]*(i-stack.top())

- Markus February 15, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

I dont think the above solution is correct. Because there is no corelation between the Rows. In the Histogram problem, the base is fixed. So the number indicates number of consecutive ones from the Base.

Consider:
1 1 1 0 0 0
1 1 1 0 0 0

So maximum is 6.

Consider:
1 1 1 0 0 0
0 0 0 1 1 1

For both these cases the histogram of number is 1s will be 3 and both the area will be six. This is wrong

- Laxman March 20, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

can you explain how your solution will work on this case 3 2 1 1 ? If I understand you right your output will be 3 instead of 4?

- Ann March 24, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

I have modified his logic little bit and write the code in c# which is working fine now.

The update logic is :

We will find out the histograms row by row from max row to 0, each time, we will calculate the max rectangle area in the input histogram.

using System;

namespace RectangleFinder
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            var random = new Random();
            sbc:
            int rowSize = random.Next(1, 10);
            int colSize = random.Next(1, 10);
            int[][] binaryMatrix = new int[rowSize][];
            for (int i = 0; i < rowSize; i++)
            {
                binaryMatrix[i] = new int[colSize];
            }
            for (int i = 0; i < rowSize; i++)
            {
                for (int j = 0; j < colSize; j++)
                {
                    binaryMatrix[i][j] = random.Next(0, 2);
                }
            }
            Print(binaryMatrix);
            int maxSize = 0;
            int[] oldHistogram = new int[colSize];
            int[] newHistogram = new int[colSize];
            for (int j = 0; j < colSize; j++)
            {
                oldHistogram[j] = 0;
            }
            for (int i = rowSize - 1; i >= 0; i--)
            {
                for (int j = 0; j < colSize; j++)
                {
                    if(binaryMatrix[i][j] == 0)
                    {
                        newHistogram[j] = 0;
                    }
                    else
                    {
                        newHistogram[j] = 1 + oldHistogram[j];
                    }
                }
                int newMax = FindLargestRectangle(newHistogram);
                if (newMax > maxSize)
                {
                    maxSize = newMax;
                }
                for (int j = 0; j < colSize; j++)
                {
                    oldHistogram[j] = newHistogram[j];
                }
            }
            Console.WriteLine("Max area of the rectangle is : {0}", maxSize);
            Console.ReadLine();
            goto sbc;

        }

        public static void Print(int[][] binaryMatrix)
        {
            int rowCount = binaryMatrix.Length;
            int colLength;
            for (int i = 0; i < rowCount; i++)
            {
                Console.Write("[");
                colLength = binaryMatrix[i].Length;
                for (int j = 0; j < colLength; j++)
                {
                    Console.Write(" {0} ", binaryMatrix[i][j]);
                }
                Console.WriteLine("]");
            }
        }

        public static int FindLargestRectangle(int[] histogram)
        {
            int maxArea = 0;
            int k,j;
            int histLength = histogram.Length;
            int isbreak;
            for(int i = 0 ; i < histLength; i++)
            {
                k = i-1;j = i+1;
                while(true)
                {
                    isbreak = 0;
                    if(k >= 0 && histogram[k] >= histogram[i])
                    {
                        k--;
                    }
                    else
                    {
                        isbreak++;
                    }
                    if(j < histLength && histogram[j] >= histogram[i])
                    {
                        j++;
                    }
                    else
                    {
                        isbreak++;
                    }
                    if(isbreak == 2)
                    {
                        break;
                    }
                }
                if(maxArea < (j-k-1)*histogram[i])
                {
                    maxArea = (j-k-1)*histogram[i];
                }
            }
            return maxArea;
        }

        public static bool ExistsAny(bool[] histogramIndexStatus)
        {
            int histLength = histogramIndexStatus.Length;
            for (int i = 0; i < histLength; i++)
            {
                if (histogramIndexStatus[i])
                {
                    return true;
                }
            }
            return false;
        }
    }
}

Complexity :

space : O(MAX(rowCount, ColumnCount));
Time : O(m*n*n) for m x n matrix, but we can modify the FindLargestRectangle to run in O(n) to have O(m*n) time complexity.

- sonesh June 27, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

static int FindLargestOnes(bool[,] table, int width, int height, out int x, out int y, out int w, out int h)
{
int currentmax = 0;
int[,] maxw = new int[height, width];
int[,] maxh = new int[height, width];
x = y = w = h = 0;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
{
if (table[i, j])
{
if (i == 0 && j == 0)
{
maxw[i, j] = maxh[i, j] = 1;
}
else if (j == 0)
{
maxw[i, j] = 1;
maxh[i, j] = maxh[i - 1, j] + 1;
}
else if (i == 0)
{
maxw[i, j] = maxw[i, j - 1] + 1;
maxh[i, j] = 1;
}
else
{
maxw[i, j] = maxw[i, j - 1] + 1;
maxh[i, j] = maxh[i - 1, j] + 1;
if (maxw[i - 1, j] - maxw[i, j - 1] <= 1)
{
int tmpw = maxw[i - 1, j];
int tmph = maxh[i - 1, j] + 1;
if (tmpw * tmph > maxw[i, j] * maxh[i, j])
{
maxw[i, j] = tmpw;
maxh[i, j] = tmph;
}
}
if (maxh[i, j - 1] - maxh[i - 1, j] <= 1)
{
int tmpw = maxw[i, j - 1] + 1;
int tmph = maxh[i, j - 1];
if (tmpw * tmph > maxw[i, j] * maxh[i, j])
{
maxw[i, j] = tmpw;
maxh[i, j] = tmph;
}
}
}
if (maxw[i, j] * maxh[i, j] > currentmax)
{
w = maxw[i, j];
h = maxh[i, j];
x = j - w + 1;
y = i - h + 1;
currentmax = w * h;
}
}
}
return currentmax;
}

- Maine January 15, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

#include <cstdlib>
#include <iostream>

//Given a 2D array of 1 and 0, Find the largest rectangle (may not be square) which is made up of all 1 or 0.

using namespace std;

#ifdef HISTOGRAM
int hist[4] = {3,2,6,8};
void find(int i)
{
     int j = i;
     int sz =0;
   
     while(hist[i] <= hist[j])
     {
        //cout << "hist[i]" << hist[i] << " i " << i << "  hist[j]" << hist[j] << " j " << j << endl;
        sz = sz + hist[i];
        if( j == 3 )
             break;
        j++;
     }
     cout << i << "th=" << sz << endl; 
}


int main(int argc, char *argv[])
{
    
    for(int i = 0; i<4 ; i++)
    {
      find(i);
            
            
    }
    
    
    
    system("PAUSE");
    return EXIT_SUCCESS;
}

#endif



int hist[4][4] = 
                 {
                   {0,1,1,1},
                   {1,1,1,1},
                   {1,0,1,0},
                   {1,0,0,0},
                  };
void print(const int& j,const int& i)
{
    int szx = 0;
    int szy = 0;
    int y = 0;
    int x = 0;
    bool ff = true;
    while(hist[x + i][y + j] == hist[i][j] && y < 4)
    {

        while(hist[x + i][y + j ] == hist[i][j] && x < 4)
        {
          x++;                 
        }
        if (ff)
         szx = x ;
        else if(szx > x )
        szx = x ;
         ff = false;
        szy++;
        y++;
        x = 0;
       // cout << "--y--" << endl;
    }
    
      
      cout << "i,j = (" << i << " , " << j << " ) sz = (" << szx << " , "<< szy   << " )" << endl;           
}
    
 

int main(int argc, char *argv[])
{
    
    for(int i = 0; i < 4 ; i++)
    {
      for(int j = 0; j < 4 ; j++)      
      {
            print (i,j);
 
            
      }
      
    }
   // cout << hist[1][2];
    system("PAUSE");
    return EXIT_SUCCESS;
}

- ss January 21, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

DP solution provided on StackOverflow.com. Put 1726632 in search there (CC doesn't allow links in the answers). In essence this is an algorithm:

At each scan do this:

If the cell has 0 assign count=0
If the cell has 1 and is an edge cell (bottom or right edge only), assign count=1
For all other cells, check the count of the cell on its right, right-below, and below. Take the min of them and add 1 and assign that to the count. Keep a global max_count variable to keep track of the max count so far.

- DS January 13, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
Comment hidden because of low score. Click to expand.
0
of 0 votes

@thelineofcode, that's true -- sorry for not clarifying that. However a simple extension of the condition I believe solves rectangular problem as well. Namely, checking only right and down and excluding right-bottom cell should produce the desired answer. The reasoning behind that when we look for squares, we want the next square only grow when we have at least the same size on each of its sides while only for rect areas it's sufficient to grow in vert and horz directions only.

- Anonymous January 13, 2014 | Flag
Comment hidden because of low score. Click to expand.
-2
of 4 votes

It's not so simple. Consider the matrix
0 0 0
0 0 0
1 1 1
Output should be 3 but this algo will return 1 since all 1's are located on the edge.

- thelineofcode January 13, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@thelineofcode, you are right. Looked around a bit more and figured that Kadane's 2D algorithm (please lookup) is the one that applies to that. And it's very different from the one above.

- Anonymous January 13, 2014 | Flag
Comment hidden because of low score. Click to expand.
Comment hidden because of low score. Click to expand.
0
of 0 votes

@TheLineOfCode, Given link is not working. Please check.


Thanks,
Srigopal

- Srigopal Chitrapu January 13, 2014 | Flag
Comment hidden because of low score. Click to expand.


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More