Amazon Interview Question
Java DevelopersCountry: United States
@le snob, Agreed! But the public interface given in the problem does not provide a method to save the intermediate results!
This code is not correct. If you see, you are calculating the same factor (4%) at each level. Instead, while going going down one level, you have to add 4% of the previous factor. Eg: at level 0: it is 10% at level 1 nodes it is 4%, at level 2 it is 4% of 4%.....and so on. This is not happening from your code. So, you would need to maintain level as well
Correct me if I am wrong. getRecruitedMembers() gives the children of the member, who are the recruits, are we not suppose to go up the tree, to calculate the amazon amount?
This code is correct. if a member earns x amazon dollars because of his spending and y dollars because of his recruits spending then his parent will earn 4% of (x+y)
To optimise this design we could update the earn at each call to add dollars for all nodes in the path of tree
I think I have an insight here. We (or at least I) have been treating getMonthlyAmazonDollars as if it returns the total amount of actual dollars spent in the current month. ...but the name "getMonthlyAmazonDollars" implies that it returns a reward value rather than an actual value spent. So perhaps it returns 4% * the actual value spent. Then you would have to multiply by 4% again at each subsequent level excepting the 1st.
MemberPayoutUtil. function.
public double calculatePayout(Member member){
if(member==null)
return 0;
return getMonthlyAmazonDollars()/10 + calculateCommisionFromRecruite(member);
}
public double calculateCommisionFromRecruite(Member member){
if(member==null)
return 0;
double commision = 0;
for(Member recruite : member.getRecruitedMembers()){
commision += calculateCommisionFromRecruite(recruite );
}
return commision*4/100;
}
public interface Member {
public double getMonthlyAmazonDollars();
public Collection<Member> getRecruitedMembers();
}
I think the point is the percentage of rewards from recruits, and this program will be a tree. We can go through each member and get the layer number to calculate rewards.
public static double CalculatePayout2(IMember member)
{
Queue<Member> queue = new Queue<Member>();
queue.Enqueue(member as Member);
double memberDolars = 0.0;
while (queue.Count != 0)
{
Member m1 = queue.Dequeue();
memberDolars += m1.getMonthlyAmazonDollars() * GetDiscount(m1.Layer);
foreach (Member item in m1.getRecruitedMembers())
{
item.Layer = m1.Layer + 1;
queue.Enqueue(item);
}
}
return memberDolars;
}
private static double GetDiscount(int layer)
{
if (layer == 0)
return 0.1;
return Math.Pow(0.04, layer);
}
Let the given amount is X = 10%of Purchase price for a given sponsor.
In prder to calulate its total sum,
getTotalAmazonDollars(){
return X+ getRecuritersShareofAmount();
}
private int getRecuritersShareofAmount(){
int totoalAmt=0;
for(Recruiter r: getRecruiters()){
total= total+r.getRecruitmentAmount();
}
}
Sorry ....forgot to consider 4% of recruiter amount.
so the modofied
getTotalAmazonDollars(){
return X+ 0.04*getRecuritersShareofAmount();
}
If you have recruiter list in the member interface you wont be able to find the sponsors. Because every recruiter can have many recruiters but only one sponsor. So, we need another attribute of type Member who will be the sponsor of that member. Then recursively traverse through the list to pay off the sponsors.
public double calculatePayout(Member mem)
{
double myearnings = mem.getMonthlyAmazonDollars() * .1 ;
double totalCommission = 0;
if( mem.getRecruitedMembers() == null || mem.getRecruitedMembers().isEmpty())
{
System.out.println("Earnings = " + myearnings);
return myearnings;
}
else
{
for(Member m: mem.getRecruitedMembers())
{
totalCommission += calculatePayout(m);
}
System.out.println("Earnings = " + myearnings + (totalCommission * .04));
return myearnings + (totalCommission * .04);
}
}
public double calculatePayout(Member m, boolean secondary) {
if (m == null) {
return 0;
}
Collection<Member> members = m.getRecruitedMembers();
double memberDollars = 0;
if (!secondary) {
if (members != null && !members.empty()){
foreach (Member m in members) {
memberDollars += 0.04 * m.getMonthlyAmazonDollars() + calculatePayout(m, true);
}
}
return memberDollars += 0.1 * m.getMonthlyAmazonDollars();
}
else {
if (members == null || members.empty()) {
return 0.0016 * m.getMonthlyAmazonDollars();
}
else {
foreach (Member m in members) {
memberDollars += calculatePayout(m, true);
}
return memberDollars;
}
}
}
That's my solution to the problem
Design a class to represent members
class Member
{
Double AmazonMoney;
Member Recruiter;
calcMemberDiscount(Double PuchaseAmount)
{
this.AmazonMoney = 0.1*AmazonMoney;
}
calcRecruiterDiscount(Double PurchaseAmount)
{
Double Discount = 0.04*PurchaseAmount;
if(Recruiter == NULL)
{
//Do Nothing
}
else
{
Recruiter.AmazonMoney = Discount;
Recruiter = Recruiter.Recruiter;
calcRecruiterDiscount(Discount);
}
}
Now when a member purchases an item,
calcMemberDiscountn and calcRecruiterDiscount
needs to be called
Hi I am using abstract class instead of interface with test cases.
class MemberImpl extends Member
{
public int counter=1;
@Override
public double getMonthlyAmazonDollars()
{
return 1000;
}
@Override
public Collection<Member> getRecruitedMembers()
{
// TODO Auto-generated method stub
return collection;
}
public void calculatePay(Member member,double totalPurchase,double payPercent)
{
member.earnedDoller=totalPurchase*payPercent;
payPercent=calculateNextPercentage();
Collection<Member> memberCollection=member.getRecruitedMembers();
if(memberCollection==null)
memberCollection=new ArrayList<Member>();
for(Member mem:memberCollection)
{
calculatePay(mem, totalPurchase, payPercent);
}
}
public double calculateNextPercentage()
{
double cent=1;
for(int i=0;i<counter;i++)
{
cent*=.04;
}
counter++;
return cent;
}
}
/* Main Class to call */
public class MainServ11
{
public static void main(String[] args)
{
/* Creating some dummy data to test*/
Member member=new MemberImpl();
member.memberName="Anoop";
Member member1=new MemberImpl();
member1.memberName="vivek";
Member member2=new MemberImpl();
member2.memberName="nisha";
Member member3=new MemberImpl();
member3.memberName="usha";
Collection<Member> memberCollection1=new ArrayList<Member>();
memberCollection1.add(member1);
memberCollection1.add(member2);
Collection<Member> memberCollection2=new ArrayList<Member>();
memberCollection2.add(member3);
member.collection=memberCollection1;
member1.collection=memberCollection2;
MemberImpl memberImp=new MemberImpl();
memberImp.calculatePay(member,member.getMonthlyAmazonDollars(),.1);
System.out.println("done");
System.out.println(member.memberName+":"+member.earnedDoller);
System.out.println(member1.memberName+":"+member1.earnedDoller);
System.out.println(member2.memberName+":"+member2.earnedDoller);
System.out.println(member3.memberName+":"+member3.earnedDoller);
}
}
/* Out put suppose total pay is 10000 */
Anoop:100.0
vivek:40.0
nisha:40.0
usha:1.6
Just have a try. Please discuss on it.
private Double payout = 0.0;
public Double calculatePayout(Member m, int layer){
List ls_m = m.getRecruitedMembers();
if(null != ls_m && ls_m.size() > 0){
for(Member mem : ls_m){
payout += Math.pow(0.04,layer)*mem.getMonthlyAmazonDollars();
calculatePayout(mem, layer++);
}
}
return payout;
}
Other solutions are similar, but this uses a technique I discovered today to track the level as we perform the BFT. As level increments, we can calculate exponential of 4% more accurately.
interface Member {
public double getMonthlyAmazonDollars();
public Collection<Member> getRecruitedMembers();
}
class MemberPayoutUtil implements Member {
private MemberPayoutUtil[] children;
public MemberPayoutUtil(MemberPayoutUtil[] children) {
this.children = children;
}
public int getNumChildren () {
return children.length;
}
public MemberPayoutUtil getChild(int index) {
return children[index];
}
public double getMonthlyAmazonDollars() {
return 10000.00;
}
//returns breadth-first traversal of recruited members in collection
public Collection<Member> getRecruitedMembers() {
Collection<Member> collection = new LinkedList<Member>();
Queue<MemberPayoutUtil> queue = new LinkedList<MemberPayoutUtil>();
queue.add(this);
int levelCounter = 0;
int level = 0;
while(!queue.isEmpty()) {
MemberPayoutUtil node = queue.remove();
collection.add(node);
for (int i = 0; i < node.getNumChildren(); i++ ) {
queue.add( node.getChild(i) );
}
}
return collection;
}
//as percentage of getMonthlyAmazonDollars
public double calculatePayout() {
double payout = 0;
Queue<MemberPayoutUtil> queue = new LinkedList<MemberPayoutUtil>();
queue.add(this);
int levelCounter = 0;
int level = 0;
while(!queue.isEmpty()) {
MemberPayoutUtil node = queue.remove();
//could print name or id here.
payout += .1 * getMonthlyAmazonDollars();
for (int i = 0; i < node.getNumChildren(); i++ ) {
queue.add( node.getChild(i) );
}
if( levelCounter==0 ) {
levelCounter=queue.size();
level++;
payout += Math.pow(.04, level) * getMonthlyAmazonDollars();
}
levelCounter--;
}
return payout;
}
}
Recruiter sponser graph will be tree, when you directed edge between Sponsor->Recruiter.
You can do a dfs to calculate the monthly amazon dollars.
- Wolverine April 05, 2014