Google Interview Question for Software Engineer / Developers


Country: United States
Interview Type: Phone Interview




Comment hidden because of low score. Click to expand.
12
of 18 vote

It's not hard to see that C(n) has the following recursive definition (similar to the Fibonacci numbers):
C(0)=1
C(1)=1
C(2)=2
C(n)=C(n-3)+C(n-2)+C(n-1) (if n>2)

This recursive definition leads to an obvious (and slow) algorithm for computing C(n). Slightly better is:

def C(n):
   L=[1,1,2]
   while n:
       n-=1
       new=L[0]+L[1]+L[2]
       L[0]=L[1]
       L[1]=L[2]
       L[2]=new
   return L[0]

This is okay, but still slow if n is very large. Faster algorithms can be found using linear algebra, similar to fast algorithms for the Fibonacci numbers. One way to regard the previous algorithm is to think of L=[1,1,2] as a vector, and then each iteration replaces L by M*L, where M is the matrix

[0 1 0]
[0 0 1]
[1 1 1]

So what we are really doing is computing the first entry of (M^n)*L. Fast algorithms for matrix exponentiation can accelerate this much faster than just repeatedly multiplying (on the left) by M, n times in a row.

- skeptical.scientist January 05, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

C(0) = 1?

+1 though.

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

Yes, C(0)=1. There is exactly 1 way to take 0 items: just sit there. Also, if C(0) is defined at all, it must be defined as 1 in order to satisfy the recurrence relation at n=3.

However, if having C(0) defined bothers you that much, you could start the definition at 1:
C(1)=1
C(2)=2
C(3)=4
C(n)=C(n-3)+C(n-2)+C(n-1) (if n>3).

- skeptical.scientist January 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Don't buy your argument for defining C(0) to be 1.

Yes, it fits neatly with the identity, but your argument is bogus.

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

For n=4.. you have to take 1,2 or 3.. So for n=1 , you have to take nothing.. so C(1) = 0.. C(2) = 1 ( {1, 1}), C(3) = 3 ({1,1,1},{2,1},{1,2})... and by your algo: C(4) = C(3) + C(2) + C(1) which gives 4(3+1+0) .. And also C(5) = 15 and by your algorithm it is 13.. a wrong answer..

- cobra January 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Why is the argument for C(0) = 1 bogus? There is exactly one way to take 0 items. I would argue that the real base cases should be C(0) = 1, C(all negative numbers) = 0. The logic here is that if you're left with no items, there's only one thing to do - nothing - and if you've used more items than you have, then you're in an invalid state and there are 0 ways to proceed from there.

Before you decide that this is unreasonable, consider how you'd even solve this problem if the problem wasn't asking you to choose items in groups of 1, 2, or 3, but in groups of 1, 2, ..., or 100. How would you get all the base cases? C(1) would be 1 because if you take 1 you're left in a valid state (0 items left); take any more and you're in an invalid state. Similarly C(2) would be 2 because taking 1 or 2 leaves you in a valid state. C(3) would be 4 because you'd consider C(0) + C(1) + C(2) -- the three possible numbers of remaining items that leave you in a valid state. The C(0) term corresponds to the possibility of taking all 3 items at once. C(4) would then be 8 since it would be C(0) + C(1) + ... + C(3). Again, the C(0) term corresponds to the possibility of taking all 4 items and so should be set to 1 for the equation to make sense.

- eugene.yarovoi January 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Well, one could argue that doing nothing, is well, doing nothing and so there are _no_ ways to take 0 items and hence C(0) = 0.

What you say is not a formal mathematical proof. (How do you even formalize your statements?)

It might be a good _convention_ to define C(0) to be 1, but you haven't proved anything i.e. It might be reasonable to _define_ C(0) to be 1, but it is just that. A definition.

A more convincing argument (to me at least) as to why we must define C(0) to be 1, is the generating function approach.

C(n) is the coefficient of x^n in (x + x^2 + x^3)^n.

This is exactly 1, in the case of n = 0 (note that in some approaches to definitions of real numbers, x^0 = 1 is just an axiomatic definition).

This way we map C(0) to the empty _product_ and then it makes sense to define it to be the multiplicative identity, which is 1.

Anyway... this is off-topic.

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

Yes, I'm aware it's just a definition.

All I'm arguing is that defining C(0) = 1 can be a part of a reasonable method for solving this problem. In fact, making this definition and further defining C(anything negative) = 0 is a solution that has fewer base cases and that also, in some sense, explains the origin of the base cases in skeptical_scientist's initial answer.

There's a reason why nowhere in my reply do I claim that I have given a rigorous mathematical proof demonstrating C(0) = 1. I suppose whether the expression C(0) has any meaning that is mandated by this problem statement is a somewhat philosophical question.

- eugene.yarovoi January 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

No one is disputing defining c(0) =1. The issue is with the 'doing nothing' reason, posed as if it is something obvious.

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

C(0) can't be 0, as you don't know how many objects are there in bucket without checking... so in order to make sure there are no objects are left you need to make one attempt, so C(0) = 1, makes sense.

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

nt print_combinations(int n)
{
int c = 0;
if(n == 1 || n == 2 || n == 3)
return n;
c = c + print_combinations(n - 1);
return n + c;
}

- Ash January 06, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

I'm so stupid that I'm satisfied when I found the recursive relation.
Thanks for the reminder of skeptical.scientist that we could use matrix to speed up the computation.
The following is my matrix implementation together with some simple tests:

class G212
{
 public static void main(String[] args)
 {
  int[] C = new int[21];
  C[0] = 1; C[1] = 1; C[2] = 2;
  for (int i = 3; i <= 20; i++)
  {
   C[i] = C[i - 3] + C[i - 2] + C[i - 1];
   System.out.println("C(" + i + ") = " + C(i));
   System.out.println("C(" + i + ") = " + C[i]);
  }
 }

 public static long[][] matrix_multiply(long[][] A, long[][] B)
 {
  int N = A.length;
  long[][] C = new long[N][N];
  for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) for (int k = 0; k < N; k++)
  {
   C[i][j] += A[i][k] * B[k][j];
  }
  return C;
 }

 public static long[][] matrix_pow(long[][] A, int pow)
 {
  int N = A.length;
  long[][] B = new long[N][N];
  for (int i = 0; i < N; i++) {B[i][i] = 1;}
  while (pow > 0)
  {
   if (1 == (pow % 2)) {B = matrix_multiply(A, B);}
   A = matrix_multiply(A, A);
   pow /= 2;
  }
  return B;
 }

 public static long C(int N)
 {
  assert(N >= 1);
  long[][] matrix = {{1, 1, 1}, {1, 0, 0}, {0, 1, 0}};
  matrix = matrix_pow(matrix, N - 1);
  return (matrix[0][0] + matrix[1][0] + matrix[2][0]);
 }
}

- Alva0930 February 20, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@Alva0930
what is the time and space of your matrix solution?

- Anonymous October 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@Anonymous:
Since Alva's hasn't answered your time space question, I will. It's O(1) space and O(log(N)) time.

For this kind of thing, you want to work it out function by function. In this case we start with matrix_multiply since it only uses elementary operations, then work out matrix_pow since it only uses matrix_multiply and elementary ops, and finally C since it calls matrix_pow.

1) matrix_multiply() takes O(N^2) space (because of the new long[N][N]) and O(N^3) time (because of the three nested for(i,j,k < N) loops) to multiply NxN matrices. All other operations are elementary O(1) operations.
2) matrix_pow() takes O(N^2) space (because of the new long[N][N]) and O(N^3*log(pow)) time (because while(pow>0) { pow /= 2; } runs for log(pow) iterations, and in each iteration we are doing two O(N^3) matrix_multiply() calls on NxN matrices).
3) C takes O(log(N)) time and O(1) space, since it calls matrix_pow() on a 3x3 matrix with pow=N, and otherwise only does elementary operations.

- skeptical.scientist October 12, 2014 | Flag
Comment hidden because of low score. Click to expand.
2
of 2 vote

Here is a different O(log n) algorithm (i.e different from the matrix method).

I will not explain this algorithm for now, will let you guys try and figure it out. But I will explain it later (after a few days), if no one posts an explanation and someone is actually interested in knowing.

Below is some python code and its output. I am just starting to learn python, so if you have some suggestions to write differently/better, I will be glad to know

Sorry if the post gets too long.

import time # for timing test.
import math # for pow
   
# tribonacci numbers satisfy t_{n+2} = t_{n-1} + t_{n} + t_{n+1}
# we start with t_{0} = 1, t_{1} = t_{2} = 2, t_{4} = 7.
# so first few are 1, 1,2,4,7,13,24,44,81,149,274.
# check out: // oeis.org / A000073
    
# Computes tribonacci numbers in O(log n) time.
def tribonacci(n):
	t = tribonacci_log(n)
	return t[2]
   
# returns the list [t_{n+2}, t_{n+1}, t_n]
def tribonacci_log(n):
	base_case = [274,149,81,44,24,13,7,4,2,1,1]
   
	# we have this as we compute upto t_{n/2 - 4}.
	if n <= 8:
		return base_case[8-n: 11-n]
    
	t = tribonacci_log(n/2)
    
	# compute t_{n-4}, t_{n-3},t_{n-2}, t_{n-1}
	for i in (1,2,3,4):
		x = t[-3] - (t[-1]  + t[-2])
		t.append(x)
    
	# t now looks like [t_{n+2}, ..., t_{n-4}]
	# t_{n} = t[2]	
    
	rett = [];
     
	# The crux of the algorithm.
	for i in (5,4,3):
		x = t[2]*t[i] + t[1]*(t[i] + t[i+1]) + t[0]*t[i-1]
		rett.insert(0,x)
    
	rett.insert(0,sum(rett));
    
	if n%2 == 0:
		return rett[-3:]
	else:
		return rett[-4:-1]
    
# Computes tribonacci numbers using the simple linear algo.
def tribonacci_linear(n):
	t = [1,1,2]
	while n > 0:
		t_new = t[0] + t[1] + t[2]
		t[0], t[1], t[2] = t[1], t[2], t_new
		n = n-1
	return t[0]
      
def tribonacci_correctness_test(num_values):
	if num_values <= 0 :
		return;
	print "Correctness Test (", num_values, ") :"
	passed = True
	for n in range(1, num_values, 1):
		if tribonacci(n) != tribonacci_linear(n):
			print "\t Failed", n, tribonacci(n)
			passed = False
	if passed:
		print "\t Passed"
      
def tribonacci_time_test(timing_value):
	print "Timing Test (", timing_value, ") :"
	delta1, t1 = time_func(timing_value, tribonacci);
	delta2, t2 = time_func(timing_value, tribonacci_linear);
	print "\tRecursive method:", delta1;
	print "\tLinear method:", delta2;
	print "\tComparing values:", t1 == t2
   
# yeah, can make it take multiple args, whatever.
def time_func(n, func):
	before = time.time()
	ret = func(n);
	after = time.time();
	return after - before, ret;
    	
    
def main():
	max_num_values = 2500
	tribonacci_correctness_test(max_num_values)
	max_timing_value = math.pow(10, 6)
	n = 1;
	while n <= max_timing_value:
		tribonacci_time_test(n)
		n = n*10
      
if __name__ == "__main__":
	main()

And this is the output

Correctness Test ( 2500 ) :
	 Passed
Timing Test ( 1 ) :
	Recursive method: 2.14576721191e-06
	Linear method: 9.53674316406e-07
	Comparing values: True
Timing Test ( 10 ) :
	Recursive method: 5.96046447754e-06
	Linear method: 3.09944152832e-06
	Comparing values: True
Timing Test ( 100 ) :
	Recursive method: 1.59740447998e-05
	Linear method: 3.40938568115e-05
	Comparing values: True
Timing Test ( 1000 ) :
	Recursive method: 3.2901763916e-05
	Linear method: 0.000290155410767
	Comparing values: True
Timing Test ( 10000 ) :
	Recursive method: 0.000332832336426
	Linear method: 0.00647592544556
	Comparing values: True
Timing Test ( 100000 ) :
	Recursive method: 0.0115561485291
	Linear method: 0.333210945129
	Comparing values: True
Timing Test ( 1000000 ) :
	Recursive method: 0.437210083008
	Linear method: 29.7244770527
	Comparing values: True

- python_learner January 06, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

The comments around the for i in (1,2,3,4) are not exactly right.

The n there should actually be n/2.

The next for loop (in (5,3,4)) is the one that computes t_n.

- python_learner January 06, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Yes, this works!

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

I ran it and it works.

Suggestion: IN the timing test, print the time immediately after running the test. This was you can see that the recursive version is fast, but the linear one is slow.

A note: we can get best of both worlds by modifying tribonacci to call linear for small values, and log for the rest.

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

Awesome!

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

Amazing! Why does it work? Can someone please explain? python_learner, are you there?

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

Python seems so cryptic. Your code is hard to understand.

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

I tried it and it works. Now can someone(anyone?) please explain why?

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

"But I will explain it later (after a few days), if no one posts an explanation and someone is actually interested in knowing."
Ha. Haha. Ha.
I guess I'll have to figure it out myself.
This is based on the recurrence C(n+m) = C(n)C(m-3)+C(n+1)(C(m-3)+C(m-4))+C(n+2)C(m-2). The recurrence is easily proved by induction on m. By using this recurrence, you can find C(2n), C(2n+1), C(2n+2) in terms of C(n), C(n+1), C(n+2) in O(1) time. This gives an O(log(n)) algorithm for computing C(n).

The way this works in the python code here is by substituting m=n, n+1, n+2 in this recurrence relation, to get equations for C(2n), C(2n+1), C(2n+2) in terms of C(n-4)...C(n+2). On input k, set n = k//2, so k==2n or k==2n+1. The function is first called recursively to determine C(n)...C(n+2), then the standard recurrence relation C(n+3) = C(n)+C(n+1)+C(n+2) is applied backwards to find C(n-4)...C(n-1). Then the three equations can be applied to find C(2n), C(2n+1), C(2n+2). Finally the algorithm returns either [C(2n+2), C(2n+1), C(2n)] or [C(2n+3), C(2n+2), C(2n+1)], depending on whether k is even (so k==2n) or k is odd (so k==2n+1).

- skeptical.scientist October 12, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

"Python seems so cryptic. Your code is hard to understand."
I disagree. Python is normally very readable. It's just this code in particular which is cryptic, not the language in general.

- skeptical.scientist October 12, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

This problem is similar to coin change problem .. you can solve it using DP
value is the array containing all the possible values

C(n,i) = C(n,i+1)+c(n-value[i],i+1) // Recursive solution

- avikodak January 05, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Yes, you are correct. This problem is similar to coin change problem, where we have unlimited supply of coins of value 1, 2, 3 and we have to find total number of ways to make sum as 'n'.

First thought that came to my mind

:-)

- Nitin Gupta January 08, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Print out the selections:

void Choice(int& choice, int count, int cur, int arr[], int& pos)
{
if (count == cur)
{
int sum = 0;
for (int i = 0; i< count && sum < count; ++i)
{
printf("%d,", arr[i]);
sum += arr[i];
}
printf("\n\n");
++choice;
return;
}
else if (count < cur)
{
return;
}
else
{
for (int i = 1; i < count; ++i)
{
arr[pos] = i;
Choice (choice, count, i + cur, arr, ++pos);
--pos;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
const int pickNum = 4;
int arr[pickNum];
int choice = 0;
int pos = 0;
Choice(choice, pickNum, 0, arr, pos);

printf("C(N) = %d\n", choice);
return 0;
}

- glk January 06, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public static int countC(int n) {
		int ways = 0;
		if(n>2) {
			ways += countC(n-3);
			ways += countC(n-2);
			ways += countC(n-1);
		} else
		if(n>1) {
			ways += countC(n-2);
			ways += countC(n-1);
		} else {
			ways += 1;
		}
			
		return ways;
	}

- lions January 08, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

That works. But it is extremely slow. It will take you around 10 minutes to compute C(40) with this method, and two decades to compute C(60). A better algorithm will take under a millisecond.

This is because your algorithm requires O(1.84^n) arithmetic operations to compute C(n). A reasonable algorithm will take O(n) arithmetic operations to compute C(n). A fast algorithm will take O(log n) operations.

- skeptical.scientist January 08, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

You are absolutely right. Your solution is much better.

- lions January 08, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Here is a solution without recursion or DP.
Define the combinations by the number of 1s, 2s and 3s in the sequence,
eg 112 has n3 =0, n2 = 1 and n1 =2
and 1111 has n3 = n2 = 0 and n1 =4

This way we can define different combinations by n1,n2,n3,
eg for n1=2,n2=1,n3=0 the three possible combinations are:
112
121
211
the total combinations = (n1+n2+n3)! / (n1! * n2! * n3! )


The maximum possible n3 for a number n is n/n3.
So all we have to do is loop over all the possible n1,n2,n3 for the given n and add the totals along the way.

The code is:

int C(int n){
int total = 0;
for(n3 = 0; n3<= n/n3; n3++){
 for(n2 = 0; n2 = (n - 3*n3)/2;n2++){
   n1 = n - 3*n3 - 2*n2
   total += fact(n1+n2+n3)/fact(n1)*fact(n2)fact(n3)
   }
  } 
return total;
}

Criticisms and comments welcome.

- tamasir January 09, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public int CnFunc(int n){
if(n==0) return 1;
int ways = 0;
for(int i=3;i>0;i--){
if(i<=n){
ways += CnFunc(n-i);
}
}
return ways;
}

- boba January 09, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

"It's not hard to see that C(n) has the following recursive definition (similar to the Fibonacci numbers)"

Well, maybe I'm not smart enough. I'm not be able to figure out why C(n)=C(n-1)+C(n-2)+C(n-3)

for me
C(1)=1
C(2)=2
C(3)=4
C(4)=7
C(5)=10

And 7 + 4 + 2 = 13, not 10

why C(5)=10?
11111
2111
1211
1121
1112
311
131
113
32
23

Did I missed anything?

- xinkai January 11, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

ok, I missed
221
212
122
so yes, looks like the equation is correct, but can someone explain why?

- xinkai January 11, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Let's say there are n objects in the bucket. You can start by picking 1, 2, or 3. If you start by picking 1, there are C(n-1) ways to pick the remaining n-1 objects. That means there are C(n-1) ways to pick n objects, if you start by taking a single object. Similarly, there are C(n-2) ways to pick n objects if you start with taking 2 objects, and C(n-3) if you start with 3. So in total there are C(n-1)+C(n-2)+C(n-3) ways of picking n objects out of the bucket.

- skeptical.scientist January 11, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

This code print all the permutations, it can be easily changed to print the total number. Also this algorithm prints n too.

#include <iostream>
#include <sstream>

void permutation(const int n,std::string preFix = "")
{
	if (preFix.empty()) {//first time only. can be taken out of this function
		for (int i = 0 ; i < n ; ++i)
			std::cout << preFix << 1;
			std::cout << std::endl;
	}
	for(int i=2; i<=n;i++) {
		int pos=0;
		while(pos <= (n - i)) {
			int numOfOnesAfterPos=0;
			std::ostringstream num;
			std::ostringstream newPreFix;
			bool addedPos=false;
			for(int j =0 ; j<n;++j) {
				if(j == pos) {
					num << i; 
					j+=i;
					addedPos=true;
					newPreFix << preFix << num.str();
				}
				if(j<n) {
					num << "1";
				    if (addedPos) {++numOfOnesAfterPos;}
                }	
			}
			std::cout << preFix << num.str() << std::endl;			
			permutation(numOfOnesAfterPos, newPreFix.str());
			++pos;
		}
	}  
}

int main ()
{
    std::cout << "start" <<std::endl;
    permutation(7);
    return 0;
}

- Anonymous January 20, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

#include<stdio.h>
#include<stdlib.h>

void print(int arr[],int n)
{
int j;
if(n!=1)
{for(j=0;j<n;j++)
printf("%d ",arr[j]);

printf("\n");
}
}

void comb(int n ,int index)
{
static int arr[100];
if(n==0)
{
print(arr,index);
return ;
}
else if(n>0)
{
int i;
for(i=1;i<=n;i++)
{
arr[index]=i;
comb(n-i,index+1);
}
}
}



main()
{
comb(4,0);
}

- Tuhinjubcse January 20, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

#include<stdio.h>
#include<stdlib.h>

void print(int arr[],int n)
{
int j;
if(n!=1)
{for(j=0;j<n;j++)
printf("%d ",arr[j]);

printf("\n");
}
}

void comb(int n ,int index)
{
static int arr[100];
if(n==0)
{
print(arr,index);
return ;
}
else if(n>0)
{
int i;
for(i=1;i<=n;i++)
{
arr[index]=i;
comb(n-i,index+1);
}
}
}



main()
{
comb(4,0);
}

- Tuhinjubcse January 20, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public static int find(int n){
if(n < 0){
return 0;
}
if(n == 0){
return 1;
}
return find(n - 1) + find(n - 2) + find(n - 3);
}

- Anonymous January 22, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

You should use memorization to prevent exponential complexity.

- Anonymous January 22, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

int count(int n)
{
    if (n == 0) return 1;
    else if (n == 1) return 1;
    else if (n == 2) return 2;
    else return count(n-3) + count(n-2) + count(n-1);
}

- Ashish19121 January 23, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Also one more condition which I forgot to put is if n is negative then return 0

- Ashish19121 January 23, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Others have mentioned this same algorithm. It works, but takes exponential time. You can write a much more efficient algorithm.

- skeptical.scientist January 23, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Some simple memorization will cause the time to be linear. You can reduce it to logarithmic time, however (or at least a logarithmic number of arithmetic ops, which may beyond some point not be strictly O(1)).

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

Anonymous replier:
Yes, you can reduce to log(n) arithmetic ops, on input n. C(n) grows exponentially in n, so at least some of the numbers involved will have O(n) bits, and arithmetic ops will take O(n) time if n is large. So you end up with an O(n log n) algorithm that way. Since the final output has O(n) bits, every algorithm must be Omega(n), so O(n log n) is reasonably close to optimal, if it's not actually optimal.

- skeptical.scientist January 23, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

If this question appeared in some sort of programming competition, it would probably ask for the answer modulo a number fitting into an int, and then the arithmetic ops would be done modulo that number and could be assumed to be O(1). The repeated-matrix-squaring approach and the iterative linear approach would then truly be O(log n) and O(n) respectively. Otherwise, if you have to print the entire number (and nothing in the problem statement suggests otherwise), the fast matrix-based approach is O(nlogn) like you indicated (with the best known fast multiplication algorithm), and the naive iterative algorithm is O(n^2).

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

True.

- skeptical.scientist January 24, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

This can be viewed as a BFS traversal of a graph.

public static int CalculateCn(int num){
    int count = 0; 
    ArrayList<Integer> queue = new ArrayList<Integer>(); 
    queue.add(0); 
    while(!queue.isEmpty()){
        int sum = queue.remove(0); 
        if(sum == num)
            count ++; 
        else
            for(int i=1;i<=Math.min(3, num-sum);i++)
                queue.add(sum+i); 
    }
    return count; 
}

- AC4400 July 24, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Interesting, I wouldn't have thought of it as a graph problem, although I can see how it is.

However, this is a really slow brute-force solution, which takes exponential time.
C(40) = 23837527729, and C(100) = 180396380815100901214157639. If you are trying to calculate C(n) by storing and incrementing a count, you're going to have a bad time.

- skeptical.scientist July 24, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Just found it even simpler with DFS (though the complexity is not good)

public static int CalculateCn(int sum, int num){
    if(sum > num)
        return 0; 
    if(sum == num)
        return 1; 
    if(sum < num)
        return CalculateCn(sum+1, num) + CalculateCn(sum+2, num) + CalculateCn(sum+3, num); 
}

- AC4400 August 05, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

int calc(int n) {

if (n == 1) return 1;
if (n == 2) return 2;
if (n == 3) return 4;

int c1 = 1;    
int c2 = 1;
int c3 = 1;

for ( int i = n ; i > 4 ; i-- ) {
  int temp = c2;
  c2 = c1 + c3;    
  c1 = c3;
  c3 += temp;
}

return 1*c1 + 2*c2 + 4*c3;
}

- edwrodrig March 03, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

We can do this combinatorially. Since the items are all the same, we can imagine setting all the items side by side next to one another. Suppose we have 4 items, then our layout would look like:

O O O O

What we essentially want to do now is to see all possible ways we could group these items together, suppose we use a sticks to divide.

We can use 1 stick
O | O O O (1 + 3)
O O | O O (2 + 2)
O O O | O (3 + 1)

We can use 2 sticks
O | O | O O (1 + 1 + 2)
O | O O | O (1 + 2 + 1)
O O | O | O (2 + 1 + 1)

We can use 3 sticks
O | O | O | O (1 + 1 + 1 + 1)

Overall we can use anywhere from 1 to n-1 sticks. We get the closed form
C(n) = sigma (n-1) choose i where i = 1:n-1

import math

def C(n):
  totalWays = 0
  for x in range(1, n):
    totalWays += nCk(n-1,x)
  return totalWays

def nCk(n, k):
  if k == 0 or n == k:
    return 1

  return int(math.factorial(n) / (math.factorial(n-k) * math.factorial(k)))

- Sappho January 05, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

^ whoops ignore the above. didn't read the piece where we were limited to choosing out exactly 1, 2, or 3 pieces at a time

- Sappho January 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
-1
of 3 vote

public class Program15072768 {

	
	
	static int count = 0;
	
	
	static void C(int n,int tsum)
	{
		if(tsum == n)
		{
			count++;
			return;
		}
		else if(tsum > n)
		{
			return;
		}
		else{
			
			for(int i=1;i<n;i++)
			{
				
				C(n,i+tsum);
			}
		}
	}
	public static void main(String[] args) {
		 C(4,0);
		 System.out.println(count);
	}

}

- cobra January 05, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Reread the question. Items can be taken 1, 2, or 3 at a time, regardless of n.

- skeptical.scientist January 05, 2013 | Flag
Comment hidden because of low score. Click to expand.
-1
of 1 vote

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("enter the number of identical items greater than 0");
string s = Console.ReadLine();
int x = int.Parse(s);
int firstgroup = 1;

abc ob = new abc();

Console.WriteLine(1+ob.NumberOfways(x));




Console.WriteLine();
}
}
class abc
{
public long NumberOfways(int n)
{
long prevalue=0;
for (int c = 1; c <= 3; c++)
prevalue=prevalue+ fact(n - c) / fact(n - c - 1);
return prevalue;




}
public long fact(int number)
{
if (number == 0)
return 1;
else
return number * fact(number - 1);
}
}

}

- mazaharulhq January 05, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

pattern should be:
C(1) = 0
C(2) = 1
C(3) = 3
C(4) = 7
C(5) = 15

which follows a trend of powers of 2. So it is just 2^(n-1) - 1

Solution is:

int C(int n)
{
return pow(2,n-1) - 1;
}

- prince of persia February 09, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

C(1)=1: take 1
C(2)=2: take 2, or 1+1
C(3)=4: take 3, 2+1, 1+2, or 1+1+1
C(4) is 7, as in the problem statement.
C(5)=13: take 3+2, 2+3, 3+1+1, 1+3+1, 1+1+3, 2+2+1, 2+1+2, 1+2+2, 2+1+1+1, 1+2+1+1, 1+1+2+1, 1+1+1+2, 1+1+1+1+1

Try again.

- skeptical.scientist February 09, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Ah my mistake. I thought you could take n-1 objects at a time based the example but problem statement is that you can only take 3 at a time. I was including 4+1 and 1+4 for C(5). Makes sense.

- prince of persia February 09, 2013 | Flag
Comment hidden because of low score. Click to expand.
-1
of 1 vote

Why is C(4) = 7
I mean why are we not taking 1112, 1121, 1211,2111, 2211,1122??

- Ram September 25, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

1+1+1+2 = 5 objects. We are looking at ways to take 4 objects total, not ways to take objects in 4 different sets.

- skeptical.scientist September 26, 2013 | Flag
Comment hidden because of low score. Click to expand.
-1
of 1 vote

import java.util.*;
public class Main {
	
	
	public static void main(String args[]){
		int num =4;
		int runningsum=0;
		ArrayList<Integer> perm = new ArrayList<Integer>();
		permutate(num,runningsum, perm);
	}
	
	public static void permutate(int num,int runningsum, ArrayList<Integer> perm){
		
		if(runningsum ==num){
			for(int i=0;i<perm.size();i++){
				System.out.print(perm.get(i) + " ");
			}
			System.out.println();
		}
		for(int i=1;i<=3 && i+runningsum<=num;i++){
			Integer cur = i;
			perm.add(cur);
			permutate(num,i+runningsum,perm);
			perm.remove(cur);
		}
	}
}

- nitesh.kedia5 March 17, 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