Amazon Interview Question for SDE1s


Country: United States
Interview Type: In-Person




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

This is the approach I came up with. I'm unsure if it's the optimal solution though. Would love suggestions!

Anyways, the idea is that you evaluate each kid in the circle, if he can pass an apple to someone who needs it behind him, then he does. Otherwise, if they have excess apples, then they just continue to pass it forward.

From the way the question seemed to be phrased, I took it that a pass is a single iteration through all children in the circle, so once everyone has given an apple away (if they can), then the next pass (step) starts.

#include <iostream>
using namespace std;

struct Child {
    int AppleCount;

    Child( ) { AppleCount = 0; }
    Child( int appleCount ) { AppleCount = appleCount; }
};

// Returns false if there are no apples to pass, true otherwise
bool PassApples( Child* children, unsigned childCount, unsigned appleCount ) {

    // Check our kids and see if there are more apples to be passed on
    bool needsPass = false;
    unsigned endIdx = childCount - 1;
    for( unsigned i = 0; i < childCount; ++i ) {

        int prevChildIdx;

        if( i == 0 ) 
            prevChildIdx = childCount - 1;
        else
            prevChildIdx = i - 1;

        // If the child before us has less apples than desired, pass it to him
        if( children[ prevChildIdx ].AppleCount < appleCount && children[ i ].AppleCount ) {
            children[ prevChildIdx ].AppleCount += 1;
            children[ i ].AppleCount -= 1;
            needsPass = true;
        }
        else {
            // If this child has excess apples, pass it along.
            if( children[ i ].AppleCount > appleCount ) {
                children[ i ].AppleCount -= 1;
                children[ (i + 1) % childCount ].AppleCount += 1;
                needsPass = true;
            }
        }
    }
    
    return needsPass;
}

int main(int argc, char *argv[]) {

    // @TODO: Read the values in from input, or a file or something...
    const int CHILDCOUNT = 5;
    Child children[ CHILDCOUNT ] = { 3, 4, 6, 10, 2 };

    // Find total apples
    unsigned totalApples = 0;
    for( int i = 0; i < CHILDCOUNT; ++i )
        totalApples += children[ i ].AppleCount;

    bool needsPass = true;
    unsigned numPasses = 0;
    while( needsPass ) {
        if( PassApples( children, CHILDCOUNT, totalApples / CHILDCOUNT ) )
            ++numPasses;
        else
            needsPass = false;
    }

    cout << "Total Passes: " << numPasses;

    // This is just here so that the app doesn't close before output can be seen
    char c;
    cin >> c;
}

- Bones April 10, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

passing a apple means a child giving away one apple to one of its neighbour.
Even if 2 separate children can pass apples simultaneously that will still be counted as 2 steps and not 1.

- pavi.8081 April 10, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Gotcha. Will edit tomorrow. Thanks!

- Bones April 10, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

If we are allowed to sort the sequence then after sort we can distribute the one apple to its neighbors until everybody has same.

- King@Work April 09, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

sorting is not allowed as children are sitting in Circle. Moreover when they are lazy enough to share just one apple to their neighbour, then forget about them moving around and arranging themselves in sorted order

- pavi.8081 April 10, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

// distribute task between smallest and highest 
    void distribute( size_t CPU[], size_t start, size_t end, bool direction )
    {
        for( size_t index = start; ; index++ )
        {
            if( index == end )
            {
                index = start;
            }
            if( direction )
            {
                CPU[index]++;
                CPU[index+1]--;
            }else
            {
                CPU[index]--;
                CPU[index+1]++;
            }
            if( 1 >= ::labs( CPU[start] - CPU[end] ) )
            {
                return;
            }
        }
    }
    // there is a circle of N CPU's with amount of tasks loaded on each one. 
    // Amount of tasks can be devided at N. 
    // Only one task can be passed between neihgbore CPU's in the circle
    void Test17252672()
    {
        size_t CPU[] = { 2, 9, 3, 6, 5, 1, 2 }; // sum = 28
        size_t sumBefore = 0;
        
        for( size_t i = 0; i < _countof(CPU); i++ )
        {
            sumBefore += CPU[i];
        }
        CPPUNIT_ASSERT_EQUAL_MESSAGE( "does not pass requeirements", 0, sumBefore % _countof(CPU) );

        bool isChanged = true;
        size_t minItem = CPU[_countof(CPU) - 1], maxItem = 0;

        // neighbor's exchange: share tasks between two CPU's
        for( size_t index = 0; isChanged; index++ )
        {
            size_t next = index + 1;

            if( _countof(CPU) - 1 == index )
            {
                isChanged = false;
                next = 0;
            }
            if( CPU[index] > CPU[next] + 1 )
            {
                while( 1 < (CPU[index] - CPU[next]) )
                {
                    CPU[ index ]--;
                    CPU[ next  ]++;
                }
                isChanged = true;
            }else
                if( CPU[next] > CPU[index] + 1 )
            {
                while( 1 < (CPU[next] - CPU[index]) )
                {
                    CPU[ next  ]--;
                    CPU[ index ]++;
                }
                isChanged = true;
            }
            if( CPU[minItem] >= CPU[ index ] )
            {
                minItem = index;
            }
            if( CPU[maxItem] <= CPU[ index ] )
            {
                maxItem = index;
            }
            if( _countof(CPU) - 1 == index )
            {
                index = 0;
            }
            // adjasment  min..max..min or max..min..max and max-min > 1
            if( !isChanged && 1 < ( CPU[maxItem] - CPU[minItem] ) )
            {
                // pass task throw the subchain
                distribute( CPU, min(minItem, maxItem), max(minItem, maxItem), minItem < maxItem );
                index = 0;
                isChanged = true;
            }
        }
        size_t sumAfter = 0;
        
        for( size_t i = 0; i < _countof(CPU); i++ )
        {
            sumAfter += CPU[i];
        }
        CPPUNIT_ASSERT_EQUAL_MESSAGE( "does not pass requeirements", 0, sumAfter % _countof(CPU) );
        CPPUNIT_ASSERT_EQUAL_MESSAGE( "sums must be the same", sumBefore, sumAfter );
    }

- LBaralgeen April 10, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

// Apple.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>

using namespace std;

void Pass(int arr[],int i,int N)
{
	if(i==0)
	{

		if(arr[N-1]<N)
		{
			++arr[N-1];
			--arr[i];
		}
		else
		{
			if(arr[i+1]<N)
			{
				++arr[i+1];
				--arr[i];

			}
			else
			{
				++arr[i+1];
				--arr[i];
			}
		}
	}

	if(i==(N-1))
	{

		if(arr[i-1]<N)
		{
			++arr[i-1];
			--arr[i];
		}
		else
		{
			if(arr[0]<N)
			{
				++arr[0];
				--arr[i];

			}
			else
			{
				++arr[0];
				--arr[i];
			}
		}
	}
	else
	{
		if(arr[i-1]<N)
		{
			++arr[i-1];
			--arr[i];
		}
		else
		{
			if(arr[i+1]<N)
			{
				++arr[i+1];
				--arr[i];

			}
			else
			{

				++arr[i+1];
				--arr[i];
			}
		}
	}

}
int _tmain(int argc, _TCHAR* argv[])
{
	int N=5;
	int arr[5]={3,4,6,10,2};
	int count=0;

	int flag=1;
	while(flag)
	{
		for(int i=0;i<N;i++)
		{
			if(arr[i]>N)
			{

				++count;

				Pass(arr,i,N);


			}
		}
		int j;
		for(j=0;j<N;j++)
		{
			if(arr[j]!=N)
			{
				flag=1;
				break;
			}
		}
		if(j==N)
			flag=0;
	}

	std::cout<<"Number of Passes"<<cout;

	return 0;
}

- Vidya April 09, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

This does not and will not work.
what do u mean by N. ...does it stand for children or is it the mean of all the apples children have, i.e. (total apples)/Children ?

- pavi.8081 April 10, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Moreover...your solution is too slow for this question. can u come up with a better one. Its pathetically slow. and wrong as well

- pavi.8081 April 10, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

use dequeue insert (n/2) element in the queue after that we take element(n/2+1,n/2-1) similarly after that(n/2+2,n/2-2) until complete array in traverse
Condition to add element to the queue is first calculate the number of apples each person must have
n/2-x added from front end and n/2+x added from back end similarly
1 if first apples is greater than average then it remove the elements from queue until all the additional apples is consumed .
2. if apples is less than average then add element to the queue.
complexity = O(n)
Space complexity =O(n)

- goelrinku April 09, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 2 vote

Its a variant of the problem to find the longest sub-array(circular) that adds up to zero. The array in question, then, would be a sequence of numbers such that, every number = number - (sum of all apples / number of boys).
The maximum number of steps would be = sum of all positive numbers in the subarray found from the modified array.( if you assume that multiple children handing over an apple to their neighbors as a single step).
e.g.: N = 3. and input array is [0,2,7] then modified array is [-3,-1, 4]. So the the guy on the right gave an apple to the guy on the left, guy in the middle gave an apple to guy on left at the same time and so on. so total steps = 4.

- nik April 10, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

In the OP example, where there are
N = 5
Total Apples = 25
Original Array [3, 4, 6, 10, 2]

If # = # - (total/N) wouldn't the Modified Array be [-2, -1, 1, 5, -3]
The sum of the positive values = 6.... in my solution I got 5 steps... am I missing something?

- Bones April 10, 2013 | Flag
Comment hidden because of low score. Click to expand.
-1
of 1 vote

Assumption = (if you assume that multiple children handing over an apple to their neighbors as a single step).

IS NOT ALLOWED

- pavi.8081 April 10, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

This is incorrect.
The example: [0,0,5,0,0]. Totally 6 steps are needed.

- xiaoxipan April 14, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@xiaoxipan my solution below works for your examples.
basically i find the closest pair of children where one has extra balls and the other missing balls, and then transfer balls between them.

- gen-y-s April 15, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

This problem is similar to BALIFE on SPOJ
See solution here GitHub/saurabhksingh/SPOJ-Code/blob/master/src/com/dev/saurabh/BALIFE.java

- Saurabh Kr Singh April 10, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

divide the group(circle) into two district and calculate the net flow needed between two districts, and then divide each district into two smaller districts and calculate the net flow between them and also update the net flow between the lager district. Keep doing this till we reach the smallest individual and then we know what should be the flow.

- Ares.Luo.T April 10, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Suppose T is the total number of balls and T/N=X.
Build a graph where each node corresponds to a child which doesn't have X balls.
The edges of the graph are the distances between each pair children (in the shortest direction around the circle) where one child has more than X balls and the other less ten X balls (there are no edges between children that both have more than X balls, or less then X balls).

Now pick the shortest edge, and remove it from the graph. Add to the total cost the distance of the edge multiplied by the number of balls moved, which is the minimum number required to get at least one of the children to X balls (example: first child has X+2 balls, second child X-3 balls, so we move two balls from the first child to the second). Remove the child with X balls from the graph. Repeat for all edges in the graph.

Total time is O(E log E), where E=O(N^2) so it's O(N^2 log N).

- gen-y-s April 10, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

def circle_dist(l):
  org_len=len(l)
  if sum(l)%org_len>0:
    return None
  avg=sum(l)/org_len
  l=[[orgpos,val-avg] for orgpos,val in enumerate(l) if val!=avg]
  s=0
  while len(l)>0:
    #print l
    min_dist=None
    prev_pos, prev_val = l[-1]
    prev_pos-=org_len
    for idx in xrange(len(l)):
      pos = l[idx][0]
      val = l[idx][1]
      if val*prev_val<0:
        if min_dist==None or pos-prev_pos<min_dist:
          min_dist=pos-prev_pos
          min_idx=idx
      prev_pos=pos
      prev_val=val

    val=l[min_idx][1]
    prev_val=l[min_idx-1][1]
    xfr=min(abs(val), abs(prev_val))
    s=s+xfr*min_dist
    #print min_idx, min_dist, xfr

    if val>0:
      val-=xfr
    else:
      val+=xfr
    if val==0:
      del l[min_idx]
    else:
      l[min_idx][1]=val

    if prev_val>0:
      prev_val-=xfr
    else:
      prev_val+=xfr
    if prev_val==0:
      del l[min_idx-1]
    else:
      l[min_idx-1][1]=prev_val

  return s

def main():
  l=[3,4,6,10,2]
  print l
  print circle_dist(l)

- gen-y-s April 12, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Explanation of the above solution:
We keep a list of only the children that have extra balls or missing balls. So each item in the list stores the original poisition of the child in the circle, and the number of extra ro missing balls the child has.
In each iteration we find the two closest children (by comparing their original positions) where one has extra balls and the other has missing balls, and then we transfer balls from the child with the extra balls to the child with the missing balls, so that at least one of them has the required number of balls. That child is then removed from the list.
We repeat the above until the list is empty.
Time complexity: O(N^2), space O(N) although the input list can be used for storage required during the computation, so no extra space would be required.

- gen-y-s April 12, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

This is incorrect.
Take the example: [1,1,1,1,2,1,0,2,1,0,1,1,1,1]
The minimal steps are 4.
Your result gives 6.
The point is, you cannot just choose the "two closest children".

- xiaoxipan April 14, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

yes, you're right.
But it's still the best solution given by any of the approximation algorithms here, right ?

- gen-y-s April 15, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

"N boys are sitting in a circle ... number of the apples can be divided by N"

Zero :-) if each boy holds two apples.

- Alex April 10, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

1.Divide the circle into 2 groups of equal size if even, or one group can be 1 larger if odd.
2.Calculate the diff between 2 groups to make the average apples per child equal
3. do the same for each of the 2 groups until the number of children in the group goes down to one.
4. adds up diffs at different levels between groups, that is the answer: Minimum moves

- Yali Zhu April 11, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public class NBoysCircle {

	public static void main(String[] args) {
		int[] array = {3,4,6,10,2};
		int sumOfArray = 3+4+6+10+2;
		int distribution = sumOfArray/5;
		
		array = recursiveDivideEqually(array.length, array, distribution);
		
		for(int i =0; i<array.length; i++) {
			System.out.println (array[i]+",");
		}
	}
	
	public static int[] recursiveDivideEqually(int totalCount, int[] array, int distribution) {
		
		boolean arrayModified = false;
		for(int i =0; i<totalCount; i++) {
			int nextIndex = 0;
			int previousIndex = 0;
			if(i == totalCount-1) {
				nextIndex = 0;
			}else {
				nextIndex = i+1;
			}
			if(i == 0) {
				previousIndex = totalCount-1;
			}else {
				previousIndex = i-1;
			}
			
			if(array[i] < distribution) {
				if(array[nextIndex] > distribution) {
					array[i] = array[i] + 1;
					array[nextIndex] = array[nextIndex] - 1;
					arrayModified = true;
				}else if(array[previousIndex] > distribution) {
					array[i] = array[i] + 1;
					array[previousIndex] = array[previousIndex] - 1;
					arrayModified = true;
				}else {
					array[i] = array[i] + 1;
					array[nextIndex] = array[nextIndex] - 1;
					arrayModified = true;
				}
			}else if (array[i] > distribution) {
				if(array[nextIndex] < distribution) {
					array[i] = array[i] - 1;
					array[nextIndex] = array[nextIndex] + 1;
					arrayModified = true;
				}else if(array[previousIndex] < distribution) {
					array[i] = array[i] - 1;
					array[previousIndex] = array[previousIndex] + 1;
					arrayModified = true;
				}
			}
		}
		if(arrayModified) {
			recursiveDivideEqually(totalCount, array, distribution);
		}
		return array;
	}

}

- Raghu April 11, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Note that for all applicable solutions( not necessarily the minimal one), they share the same property: the net flow for each child is invariant.
So two solutions differ from a flow whose net flow for each child vanishes, that is, a circumfluence like 1->1->...->1.
To find the minimal solution, just start from any initial solution, subtract a circumfluence from it, to minimize the difference between the number of positive edges and negative edges. The constant flow in the circumfluence is the median of the flows in the initial solution.

Take [5,0,0,0,0] as an example, an initial flow is [4,3,2,1,0], with 10 steps. subtract the circumfluence [2,2,2,2,2] from it, we get a flow [2,1,0,-1,-2], with 6 steps. This is the minimal solution since it has equal number of positive edges and negative edges: 2.
The time complexicity is O(n).

- xiaoxipan April 15, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

It's not clear what does [2,1,0,-1,2] mean ? How does it describe the actual solution ?

Also why did you decide to sunstract [2,2,2,2,2] from the intial solution, and how would your algorithm work for the input of [1,1,1,1,2,1,0,2,1,0,1,1,1,1] ?

- gen-y-s April 16, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

[2,1,0,-1,-2] means: boy[0] gives 2 apples to boy[1] and boy[4] each. Then boy[1] gives 1 apple to boy[2]. boy[4] give 1 apple to boy[3].
2 is the median of [4,3,2,1,0]. So we need to subtract [2,2,2,2,2] from that.
for [1,1,1,1,2,1,0,2,1,0,1,1,1,1], the initial flow is:
[0, 0, 0,0,1,1,0,1,1,0,0,0,0,0]
That is: boy[4] gives 1 apple to boy[5], boy[5] passes it to boy[6], and so on.
The median of this array is 0, which means we need to subtract [0,0,....,0] from it, which means we don't need to update this initial solution. It is already optimal.

- xiaoxipan April 16, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

In the worst case, one boy has all the apples and distributes it around the circle, 1 at a time. So if N is even, in the worst case the number of passes around the circle would be:
Number of passes = N/2 + 2(N/2 - 1) + 2(N/2 - 2)..so on as long as N/2 - 2 > 0
If N is odd:
Number of passes = 2(N/2) + 2(N/2 - 1) + 2(N/2 - 2)..so on as long as N/2 - 2 > 0
"/" is the division operator.

- lakshmi April 19, 2013 | 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