Amazon Interview Question for Software Engineer / Developers


Country: Vancouver
Interview Type: Written Test




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

//use a queue of size 10 to store each customers data
void updateReadingSpeeds(String customerID, String bookID, int pageNumber)
var queue = getCustomerQueueById(customerID, bookID) //composite key
queue.pop();
queue.enqueue(pageNumber);
save(queue);

void printLeaderboard(String bookID)
var queue = getQueuesByBookId(bookID)
var iterator = queue.iterator();

Iterator listGroupedBySpeed = groupBySpeed(iterator);
Iterator sortedListBySpeed = sort(iterator);
foreach(item in sortedListBySpeed)
print(item)

def sort // sorts by reading speed. trivial implementation
def groupBy //returns new list of items indexed by reading speed. trivial implementation

- Anonymous June 29, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

formatted:

//use a queue of size 10 to store each customers data 
void updateReadingSpeeds(String customerID, String bookID, int pageNumber) 
   var queue = getCustomerQueueById(customerID, bookID) //composite key 
   queue.pop(); 
   queue.enqueue(pageNumber); 
   save(queue); 

void printLeaderboard(String bookID) 
   var queue = getQueuesByBookId(bookID) 
   var iterator = queue.iterator(); 

   Iterator listGroupedBySpeed = groupBySpeed(iterator); 
   Iterator sortedListBySpeed = sort(iterator); 
   foreach(item in sortedListBySpeed)  
      print(item) 

def sort // sorts by reading speed. trivial implementation 
def groupBy //returns new list of items indexed by reading speed. trivial implementation

- Anonymous June 29, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

I did solve this using keyed data structures which holds the problem states.

While printing leader board, I am having to iterate through all customers reading the book and that's O(N2) time complex solution + O(N log N) for sorting the N customers by reading speed time.

Clearly not the best solution, did anyone come up with anything which is highly optimized?

- Samiran Saha June 29, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

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

import std.stdio;
import std.string;
import std.algorithm;
import std.exception;

class Speed
{
	private int[]  _speed;
	private size_t _history_len;
	private int    _last_page;

	private string _customer_id;
	private string _book_id;
	
/*
	Current Time:    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15]
	Current Page:    [0, 5, 6, 8,12,15,17,21,24,27,29,31,37,42,49,52]
	Current Speed:   [0, 5, 1, 2, 4, 3, 2, 4, 3, 3, 2, 2, 6, 5, 7, 3]
	"Reading Speed": [0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 6, 7, 7] 
*/

	this(string customer_id, string book_id, size_t history_len = 10) 
	{ 
		this._customer_id = customer_id;
		this._book_id = book_id;
		this._history_len = history_len;
		this._last_page = 0;
		this._speed ~= 0;
	}

	public void set_page(int page)
	{
		int curent_speed = page - _last_page;
		if (curent_speed < 0) throw new Exception("New page can not be less then prior.");
		_last_page = page;
		if (_speed.length == _history_len) _speed = _speed[1..$];
		_speed ~= curent_speed;
	}

	public int get_max_speed()
	{		
		int max = _speed[0];
		foreach(item; _speed[1..$]) if (max < item)	max = item;
		return max;
	}

	public void read_new_book(string new_book_id)
	{
		this._book_id = new_book_id;
		this._speed.length = 0;
		this._speed ~= 0;
		this._last_page = 0;
	}

	public int[] get_history()
	{
		return _speed;
	}

	public string get_customer_id()
	{
		return _customer_id;
	}

	public string get_book_id()
	{
		return _book_id;
	}
}

unittest
{
	auto rs = new Speed("customer1", "book1");
	
	{
		write("ReadingSpeed::get_customer_id()");
		scope(success) writeln(" ok.");		
		assert("customer1" == rs.get_customer_id);
	}

	{
		write("ReadingSpeed::get_book_id()");
		scope(success) writeln(" ok.");		
		assert("book1" == rs.get_book_id);
	}

	{
		write("ReadingSpeed::set_page(int page)");
		scope(success) writeln(" ok.");		
		
		rs.set_page(5);
		assert([0,5] == rs.get_history);
		assert(5 == rs.get_max_speed);
		assertThrown(rs.set_page(4));
		foreach(page; [6, 8, 12, 15, 17, 21, 24, 27, 29, 31, 37, 42, 49, 52]) rs.set_page(page);		
		assert([2, 4, 3, 3, 2, 2, 6, 5, 7, 3] == rs.get_history); // keep only last 10 records
		assert(7 == rs.get_max_speed); 
	}

	{
		write("ReadingSpeed::read_new_book(string new_book_id)");
		scope(success) writeln(" ok.");		
		rs.read_new_book("book2");
		assert("book2" == rs.get_book_id);
		assert(0 == rs.get_max_speed);
		assert([0] == rs.get_history); 
	}

}


unittest
{
	Speed[string] hash;
	void updateReadingSpeeds(string customer, string book, int page) 
	{
		Speed speed = hash.get(customer, new Speed(customer, book));
		if (book != speed.get_book_id)  speed.read_new_book("book");		
		speed.set_page(page);
		hash[customer] = speed;
	}

	void printLeaderboard(string book) 
	{
		struct Reader
		{
			string customer;
			int speed;
		}

		Reader[] readers;
		foreach(customer, speed; hash)
		{
			if (book == speed.get_book_id)
				readers ~= Reader(customer, speed.get_max_speed);
		}

		sort!("a.speed > b.speed")(readers);
		foreach(i, item; readers)
		{
			writeln(item.customer, ", ", item.speed, ", ", (i+1));
		}
	}

	writeln("public void updateReadingSpeeds(string customer, string book, int page):");
	
	
	foreach(page; [6, 8, 12, 15, 17, 21, 24, 27, 29, 31, 37, 42, 49, 52]) updateReadingSpeeds("customer1", "book1", page);
	foreach(page; [6, 8, 12, 15, 17, 21, 24, 28, 29, 35, 36, 40, 45, 49]) updateReadingSpeeds("customer2", "book1", page);
	foreach(page; [6, 8, 12, 15, 19, 23, 26, 29, 29, 32, 34, 37, 41, 42]) updateReadingSpeeds("customer3", "book1", page);
	
	
	assert(7 == hash["customer1"].get_max_speed); 
	assert(6 == hash["customer2"].get_max_speed); 
	assert(4 == hash["customer3"].get_max_speed); 
	
	writeln("customer1: ", hash["customer1"].get_history);
	writeln("customer2: ", hash["customer2"].get_history);
	writeln("customer3: ", hash["customer3"].get_history);

	
	writeln("void printLeaderboard(string book):");
	printLeaderboard("book1");
}


void main()
{
	
}

- seb June 29, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Application output:

ReadingSpeed::get_customer_id() ok. 
ReadingSpeed::get_book_id() ok. 
ReadingSpeed::set_page(int page) ok. 
ReadingSpeed::read_new_book(string new_book_id) ok. 
public void updateReadingSpeeds(string customer, string book, int page): 
customer1: [2, 4, 3, 3, 2, 2, 6, 5, 7, 3] 
customer2: [2, 4, 3, 4, 1, 6, 1, 4, 5, 4] 
customer3: [4, 4, 3, 3, 0, 3, 2, 3, 4, 1] 
void printLeaderboard(string book): 
customer1, 7, 1 
customer2, 6, 2 
customer3, 4, 3

- Anonymous June 29, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

import java.util.ArrayList;
import java.util.HashMap;
import java.util.ListIterator;
import java.util.Map;

public class BookPageSpeed {
	static Map<String, Map<String, CustomerReadingSpeed>> bookReadingSpeed = new HashMap<String, Map<String, CustomerReadingSpeed>>();
	static Map<String, Integer> maxBookReadingSpeed = new HashMap<String, Integer>();
	static Map<String, ArrayList<ArrayList<String>>> leaderBoard = new HashMap<String, ArrayList<ArrayList<String>>>();
	
	public static void addNewBook(String bookID){
		bookReadingSpeed.put(bookID, null);
		leaderBoard.put(bookID, null);
	}
	
	public static void addNewCustomer(String bookID, String customerID){
		Map<String, CustomerReadingSpeed>  custReadingSpeed;
		CustomerReadingSpeed cust = new CustomerReadingSpeed();
		if(bookReadingSpeed.get(bookID) == null){
			custReadingSpeed = new HashMap<String, CustomerReadingSpeed>();
		}
		else{
			custReadingSpeed = bookReadingSpeed.get(bookID);
		}
		custReadingSpeed.put(customerID, cust);
		bookReadingSpeed.put(bookID, custReadingSpeed);
		maxBookReadingSpeed.put(customerID, 0);
		ArrayList<ArrayList<String>> custLeaderBoard;
		if(leaderBoard.get(bookID) != null){
			custLeaderBoard = leaderBoard.get(bookID);
		}
		else{
			custLeaderBoard = new ArrayList<ArrayList<String>>(100);
			for(int i=0; i<101; i++){
				ArrayList<String> cust_i = new ArrayList<String>();
				custLeaderBoard.add(cust_i);
			}
		}
		custLeaderBoard.get(0).add(customerID);
		leaderBoard.put(bookID, custLeaderBoard);
	}
	
	public static void updateReadingSpeeds(String customerID, String bookID, int pageNumber){
		CustomerReadingSpeed custReadingSpeed = bookReadingSpeed.get(bookID).get(customerID);
		custReadingSpeed.CustomerReadingPage.add(pageNumber);
		int size= custReadingSpeed.CustomerReadingPage.size();
		int speed = custReadingSpeed.CustomerReadingPage.get(size-1) - custReadingSpeed.CustomerReadingPage.get(size-2);
		custReadingSpeed.CustomerReadingSpeed.add(speed);
		int prev_speed = maxBookReadingSpeed.get(customerID);
		if(speed > prev_speed){
			leaderBoard.get(bookID).get(prev_speed).remove(customerID);
			maxBookReadingSpeed.put(customerID, speed);
			leaderBoard.get(bookID).get(speed).add(customerID);
		}
	}
	
	public static void printLeaderboard(String bookID) {
		int index = 100;
		int rank =1;
		System.out.print("CustomerID, Reading Speed, Rank\n");
		ListIterator<ArrayList<String>> it = leaderBoard.get(bookID).listIterator(index);
		while(it.hasPrevious()){
			int readingSpeed = it.previousIndex();
			ArrayList<String> customers = it.previous();
			if(!customers.isEmpty()){
				for(String custID: customers){
					System.out.printf("Customer %s, %d, %d\n", custID, readingSpeed, rank);
				}
				rank++;
			}
		}
	}
	
	public static void main(String[] args){
		addNewBook("A");
		addNewCustomer("A", "A");
		addNewCustomer("A", "B");
		updateReadingSpeeds("A", "A", 2);
		updateReadingSpeeds("B", "A", 5);
		printLeaderboard("A"); 
	}
}



import java.util.ArrayList;

public class CustomerReadingSpeed {

	public ArrayList<Integer> CustomerReadingPage = new ArrayList<Integer>();
	public ArrayList<Integer> CustomerReadingSpeed = new ArrayList<Integer>();

	public CustomerReadingSpeed(){
		CustomerReadingPage.add(0);
		CustomerReadingSpeed.add(0);
	}
	
}

- vandana.kcp June 30, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

A dequeue (of size 10) can be used to update reading speed in O(1).

I cant do better than O(NlogN), N - # of customers. Assuming that the speeds cannot vary much till like 10 mins the average running time can be reduced (insertioin sort for near sorted i/p or a variant of heap sort)

I would love to see a better solution for ranking(sorting) the customers :)

- Anon July 08, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

My solution works for me. The way I looked at it, we need to be able to partition on each minute. And we needed to be able to snapshot a leaderboard every minute. So I think my approach is a bit different from the others I saw on here.

First I maintain a couple hashmaps. First, booksToCustomers. This maintains the set of customers reading the keyed book. Next is the customerToPageNumbers hashmap. This map keys customers to the list of page numbers they have read to each minute.

The way I track the last N minutes of reading it by maintaining a third map: customerToSpeeds. This maps customer to a bounded array of size N (where N is the amount of history to track). So for our case, 10, since we are only interested in the last 10 minutes.

The key functions we will need are:

updateReadingSpeeds(String customerID, String bookID, int pageNumber);
printLeaderBoard(String bookID);

I've added a few helper functions to make things a bit more modular. I will explain each and my reasoning for them below.

void updateCustomerPages(String customerID, int pageNumber, int timeBucket);
void updateCustomerSpeed(String customerID, int timeBucket, int currentSpeed);
void addCustomerToBook(String customerID, String bookID);
int fetchTimeBucket();
int calculateReadingSpeed(String customerID);

The interesting function to note is fetchTimeBucket(). I did this because I figure that we will have many clients hitting us at once. The simplest way I could think of to maintain parity and ensure that all of the speeds are kept logically is to take the time and mod it with the max history time. This function only takes current time and converts it to minutes and mods it with N. This returns the bucket of time the speed should go into for any given customer.

updateCustomerPages updates the current customer for the current time bucket.
updateCustomerSpeed will update the speed array for a given customer
addCustomerToBook simply adds a customer to a book's reader list.
calculateReadingSpeed takes the current timebucket and works its way backwards (a constant number N) and calculates the highest speed over the past N minutes.


Lastly, I've also added a helper structure/static class called LeaderEntry. This is nothing more than a value object to aid in printing the leader list.

The end result is fairly simple and could definitely use work before it is ready for prime-time. But as far as answering the question goes, I think this would suffice.

Implementation follows:

Note that I've stubbed out the time function so that I could test it in the main method. The increasePages function is just a helper for faking some data.

Hope this helps.

import java.util.*;

/**
 * @author chris moran
 */
public class KindleReadingSpeed {
    private static int time = 1;
    private static final int HISTORY_TO_TRACK = 10;
    private static Random random = new Random();
    public static void main(String[] args) {
        int[] pages = new int[4];
        int timeLength = 4;//minutes
        for(int i = 0; i < timeLength; i++) {
            increasePages(pages);
            updateReadingSpeeds("customer0", "book0", pages[0]);
            updateReadingSpeeds("customer1", "book0", pages[1]);
            updateReadingSpeeds("customer2", "book0", pages[2]);
            updateReadingSpeeds("customer3", "book1", pages[3]);
            time++;
        }

//        int speed = calculateReadingSpeed("customerID");
//        System.out.println("speed = " + speed);
        printLeaderBoard("book1");
        System.out.println();
    }
    private static void increasePages(int[] pages) {
        for(int i = 0; i < pages.length; i++) {
            pages[i] += random.nextInt(25);
        }
    }
    private static final Map<String,Set<String>> bookToCustomers = new HashMap<String, Set<String>>();
    private static final Map<String,List<Integer>> customerToPageNumbers = new HashMap<String, List<Integer>>();
    private static final Map<String,int[]> customerToSpeeds = new HashMap<String, int[]>();

    static class LeaderEntry implements Comparable<LeaderEntry>{
        private String customerID;
        private int speed;
        LeaderEntry(String customerID, int speed) {
            this.customerID = customerID;
            this.speed = speed;
        }
        @Override
        public int compareTo(LeaderEntry o) {
            return o.speed == this.speed ? -1 : o.speed - this.speed;
        }
        @Override
        public boolean equals(Object o) {
            if(this == o) return true;
            if(!(o instanceof LeaderEntry)) return false;

            LeaderEntry that = (LeaderEntry) o;

            if(speed != that.speed) return false;
            if(!customerID.equals(that.customerID)) return false;

            return true;
        }
        @Override
        public int hashCode() {
            int result = customerID.hashCode();
            result = 31 * result + speed;
            return result;
        }
    }

    private static void printLeaderBoard(String bookID) {
        System.out.println("Customer ID,Reading Speed,Rank");
        if(!bookToCustomers.containsKey(bookID)) {
            System.out.println("");
            return;
        }
        Set<String> customers = bookToCustomers.get(bookID);

        Set<LeaderEntry> leaders = new TreeSet<LeaderEntry>();
        for(String customerID : customers) {
            int speed = calculateReadingSpeed(customerID);
            LeaderEntry entry = new LeaderEntry(customerID, speed);
            leaders.add(entry);//@TODO: check for failure to add!
        }
        int rank = 1;
        for(LeaderEntry entry : leaders) {
            System.out.println(entry.customerID + "," + entry.speed + "," + rank++);
        }
    }

    private static void updateReadingSpeeds(String customerID, String bookID, int pageNumber) {
        int timeBucket = fetchTimeBucket();
        addCustomerToBook(customerID, bookID);
        updateCustomerPages(customerID, pageNumber, timeBucket);
    }
    private static void updateCustomerPages(String customerID, int pageNumber, int timeBucket) {
        int currentSpeed = pageNumber;
        List<Integer> pageNumbers;
        if(!customerToPageNumbers.containsKey(customerID)) {
            pageNumbers = new ArrayList<Integer>();
        } else {
            pageNumbers = customerToPageNumbers.get(customerID);
            currentSpeed = pageNumber - pageNumbers.get(pageNumbers.size() - 1) ;
        }
        pageNumbers.add(pageNumber);
        customerToPageNumbers.put(customerID, pageNumbers);
        updateCustomerSpeed(customerID, timeBucket, currentSpeed);
    }

    private static void updateCustomerSpeed(String customerID, int timeBucket, int currentSpeed) {
        final int[] speeds;
        if(!customerToSpeeds.containsKey(customerID)) {
            speeds = new int[HISTORY_TO_TRACK];
            Arrays.fill(speeds, 0);
        } else {
            speeds = customerToSpeeds.get(customerID);
        }
        speeds[timeBucket] = currentSpeed;
        customerToSpeeds.put(customerID, speeds);
    }
    private static void addCustomerToBook(String customerID, String bookID) {
        synchronized(bookToCustomers) {
            Set<String> customers = bookToCustomers.containsKey(bookID) ? bookToCustomers.get(bookID) : new HashSet<String>();
            customers.add(customerID);
            bookToCustomers.put(bookID, customers);
        }
    }
    private static int fetchTimeBucket() {
        //Debug
        return time % 10;
//        return (int) ((System.currentTimeMillis() / 60000) % HISTORY_TO_TRACK);
    }

    private static int calculateReadingSpeed(String customerID) {
        if(!customerToSpeeds.containsKey(customerID))
            return 0;
        int max = Integer.MIN_VALUE, timeBucket = fetchTimeBucket();
        int[] speeds = customerToSpeeds.get(customerID);
        for(int j = 0; j < 10; j++) {
            int current = timeBucket - j % 10;
            if(current < 0) {
                current = 10 + current;
            }
            max = Math.max(max, speeds[current]);
        }
        return max;
    }

}

- Chris July 29, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

Two functions are required:
1) update
2) getLeaderboard.

for update the approach is straightforward. for each user maintain a map of userid and ((n(number of update events), avg speed of n events)). For new update call, using n and old avg, compute new avg read speed as: avg = ((n*avg)+readingSpeed)/n+1;n=n+1;

This new reading speed for a user needs to be updated in data structure for computing leaderboard.

Approach1:
If we are not maintaining any separate data structure for leaderboard. in that case, update event will take o(1) and computeleaderboard will take o(n^2) time.

Approach2:
if we are maintaining a treemap instead of hashmap for each user. in that case update event will take o(logn) and computeleaderboard will take o(n) time.

Apporach3:
As the reading speed values are very small in range. suppose we are maintaining speed till say first decimal place and max speed possible is say 20 pages per min. so the total possible buckets can be 200. even if we consider inhuman reading speed of say 100 pages per min it will take 1000 buckets.
We will have user data in hashmap of userid and (n,avgSpeed). For leaderboard we will have separate datastructure, i.e. array(buckets) where index corresponds to speed(eg 10.5 pages per min will be 105 index) and value at that index will be set of userids. We can just move userid from one bucket to another in case of update event. That will be o(1) and computeleaderboard will be o(n) as we need to just traverse the array. Banged!!

- hinax June 28, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

eh why average reading speed? A customer's "reading speed" is the maximum number of pages they have read in a single minute over the previous 10 minutes. Can you explain a bit? thx

- Jason June 28, 2014 | Flag


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