Interview Question


Country: United States




Comment hidden because of low score. Click to expand.
1
of 1 vote

public int numOfWay (char [][] ch){
		return solve(ch, 0);
	}
	
	private int solve (char [][] ch , int x){
		if (x >= ch.length) {
			return 1 ;
		}
		int  total = 0;		
		for (int i = 0 ; i < ch[0].length ;++i) {
			if(ch[x][i] == '*') {
				continue ;
			}
			if (isValid(ch, x, i)) {
				ch[x][i] = 'b' ;
				total += solve(ch, x + 1);
				ch[x][i] = '.' ;	
			}			
		}		
		return total ;
	}
		
	private boolean isValid (char [][] ch, int i , int j) {
		int x = i - 1 ;
		int y = j - 1 ;
		//left corner ;
		while (x >= 0 && y >= 0 && ch[x][y] != '*') {
			if (ch[x][y] == 'b') {
				return false ;
			}
			x--;
			y--;
		}
		//right corner;
		x = i - 1 ;
		y = j + 1 ;
		while (x >=0 && y < ch[0].length && ch[x][y] != '*') {
			if (ch[x][y] == 'b') {
				return false ;
			}
			x--;
			y++;
		}						
		return true ;

}

- Scott September 14, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Nice!

Actually, I also wanted to solve it with backtrack but I thought maybe the answer could be large enough that backtrack would not work and it should be solved with Dynamic Programming.

After seeing your solution I tried to generate so many random chess to see what are the ranges of large answers.

This is one of the largest I could generate:

10 10
...*.**...
.***......
.*....**..
..**..*...
....*.*...
...**.*...
.**.*.....
..........
..........
..........

the answer is: 40307036

I ran both of my solution and yours on Codeforces's server:
Your solution took 1887 ms and mine, 15 ms.
(Albeit we should keep in mind that C++ is faster than Java)

It seems backtrack is fast enough for this problem.

- MehrdadAP September 14, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Hi MehrdadAP,

if use DP, what are overlap subproblems for this question?

Thanks

- Scott September 14, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Let's say we have a 10*10 chessboard and we are at row i and now wanna check whether it's possible to put a bishop at column j or not. As an example let i=3,j=4.

Basically, there are one primary diagonal and one secondary diagonal that can threat cell (3,4). Primary diagonal is (0,1) (1,2) (2,3). it doesn't matter if there is bishop in (0,1) or (1,2) or (2,3), we just need to know is there any bishop in one of them or not, and that's where we have overlapped sub-problems. The same thing is true for secondary diagonals.

When we are at row i, we just need to know the information of M primary diagonals and M secondary diagonals. (by information, I mean whether they have a bishop that can threat row i's cells).So every time we just need to pass the information of M primary diagonals and M secondary diagonals to next row.

So I define dp like this:
dp[i][state1][state2] = that means in how many ways I can put bishops from row i to the end. And also we know about the constraints in state1(for primary diagonals) and state2(for secondary diagonals).

For handling blocked cells, when I'm at row i, I iterate through its cells, and when I reach at a blocked cell, I free those diagonals that have the current blocked cell in them. (since previous bishops can no longer threat any other cells after current blocked cell)

So state1 and state2 each can have 2^M different values. Since M,N<=10, we could use memoization technique to store answer of states.

Moreover, in the case that M,N>10 we can ignore storing the state in memory(since it's large) and just use the recursion which is much faster than your backtrack.

I posted my implementation, so you can see it for more clarification. I tested my solution with different random chess and the answers were the same as your implementation, therefore you could safely trust it :D

- MehrdadAP September 15, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

UPD: I optimized my code, now it works in O(N*2^N*2^N). I added UPD part at the end of my old explanations.

Here's my not-optimal DP solution:
It's O(N*2^(4*N)), which for this problem is O(10*2^40)

dp[i][state1][state2] = number of ways of putting bishops in rows>=i while state1 shows the state of primary diagonals and state2 show the state of secondary diagonals.

with one iteration I free those diagonals that are blocked by cells of current row.
and then I add answer of putting a bishop in current row and going to next row.


UPD:

I realized that when we are at row i, we actually don't need to know about state of every diagonal. all we nned is to know about the diagonals which can threat current row.
So we just need to know about N primary diagonals and N secondary diagonals. So the total complexity is N*2^N*2^N which is 10*2^20 ~ 10^7 which is fine for this problem.

/*
MehrdadAP
Count number of ways of putting exactly one bishop in a chess with obstacles.

O(N*2^N*2^N)

*/

#include <iostream>
#include <string.h>

using namespace std;

const int maxn = 10;
int N,M;
int dp[maxn][1<<maxn][1<<maxn];
char grid[maxn][maxn];

int solve(int row,int state1,int state2)
{
	
	if (row==N) return 1;
	
	//we actually don't need all the information of
	//state1 and state2, so we can reduce them to ss1 and ss2
	
	//to make the implementation easier, I use state1 and state2 
	//when pass it to next row, but for stoing in dp table, I use
	//ss1 and ss2 

	int ss1=0,ss2=0;
	for (int col=0;col<M;col++){
		int diagInd = ( row<=col ? col-row : row-col+M-1);
		int diagInd2= row+col;

		if ((state1 & (1<<diagInd))!=0)
			ss1 |=(1<<col);

		if ((state2 & (1<<diagInd2))!=0)
			ss2 |=(1<<col);
	}

	int &ref = dp[row][ss1][ss2];
	if (ref!=-1)
		return ref;


	for (int col=0;col<M;col++){
		int diagInd = ( row<=col ? col-row : row-col+M-1);
		int diagInd2= row+col;

		if (grid[row][col] == '*'){
			state1 &= ~(1<< diagInd);
			state2 &= ~(1<<diagInd2);
		}
	}


	int ans=0;
	for (int col=0;col<M;col++){
		int diagInd = ( row<=col ? col-row : row-col+M-1);
		int diagInd2= row+col;

		if (grid[row][col]== '*') continue;

		if ((state1 & (1<<diagInd))==0 && (state2 & (1<<diagInd2))==0 ){
			ans+= solve(row+1,state1 | (1<<diagInd) , state2 | (1<< diagInd2));
		}
	}

	//cout << row << " " << state << " " <<ans << endl;
	return ref = ans;
}


int main()
{

	while (cin >> N >> M){

		for (int i=0;i<N;i++)
			for (int j=0;j<M;j++)
				cin >> grid[i][j];

		memset(dp,-1,sizeof dp);

		cout << solve(0,0,0) << endl;

	}
	


	return 0;
}

- MehrdadAP September 13, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Its like n queen problem with extra obstracles condition added.

- coder September 14, 2015 | Flag Reply


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