Plaid Phone Interview
Anonymous User
11751

The technical phone screen consists of 2 rounds. The question is read over the phone and you need to jot down the points carefully. You will asked to share your screen and email them the code after the interview (which is wierd, because you have 2 interviewers for each round looking at your code and still wants you to send them the Solution file. May be they will run it some inputs on thier end and decides whether to select you or not)

I dont remember the exact problem statement, as it is read over the phone (no where pasted or shown). Posting the solutions just for reference and hoping if someone could understand it from my comments.

Round 1

The question is to find recurring transactions. Please refer to the comments in the code below more info!

package random;

import java.util.*;

/*

Part 1
Minimum 3 transactions are required to consider it as a recurring transaction
Same company, same amount, same number of days apart - recurring transactions

Input: Company, Amount, Timestamp (Day of the transaction)
Output: An array of companies who made recurring transactions

Part 2
The amounts and timestamps - similar
20% higher than minimum

(minimum of all amount) 10$ + 20% -> 12$
[10, 11, 12]

[
  ("Netflix", 9.99, 0),
  ("Netflix", 9.99, 10),
  ("Netflix", 9.99, 20),
  ("Netflix", 9.99, 30),
  ("Amazon", 27.12, 32),
  ("Sprint", 50.11, 45),
  ("Sprint", 50.11, 55),
  ("Sprint", 50.11, 65),
  ("Sprint", 60.13, 77),
  ("Netflix", 9.99, 50),
]

Map<String, List<Transaction>>

Transaction {
    double amount;
    int timestamp;
}

Sprint
[50, 50, 50, 60] ->

Amazon ->

Netflix
[9, 9, 9]
[10, 20, 30, 50] -> {10, 10, 20} ->

Number of items ->
Max timestamp -> Integer

 */
public class Solution {
    public static class Transaction {
        String company;
        double amount;
        int timestamp;

        public Transaction(String company, double amount, int timestamp) {
            this.company = company;
            this.amount = amount;
            this.timestamp = timestamp;
        }
    }

    public List<String> getCompaniesWithRecurringTransactions(Transaction[] transactions) {
        List<String> companies = new ArrayList<>();
        if(transactions == null || transactions.length == 0) {
            return companies;
        }

        Map<String, List<Transaction>> transactionsMap = new HashMap<>();
        for(Transaction t : transactions) {
            List<Transaction> listOfTransactions = transactionsMap.getOrDefault(t.company, new ArrayList<>());
            listOfTransactions.add(t);
            transactionsMap.put(t.company, listOfTransactions);
        }

        for(String company : transactionsMap.keySet()) {
            List<Transaction> listOfTransactions = transactionsMap.get(company);
            if(listOfTransactions.size() < 3) {
                continue;
            }

            if(hasRecurringTransactions(listOfTransactions)) {
                companies.add(company);
            }
        }

        return companies;
    }

    private boolean hasRecurringTransactions(List<Transaction> transactions) {
        double minAmount = getMinimumAmount(transactions);
        double maxAmount = minAmount + (minAmount * 0.2);

        int minDays = getMinimumDays(transactions);
        int maxDays = minDays + (int) (minDays * 0.2);

        int prevTimestamp = transactions.get(0).timestamp;

        for(int index = 0; index < transactions.size(); index++) {
            double curAmount = transactions.get(index).amount;
            if(minAmount > curAmount || curAmount > maxAmount) {
                return false;
            }

            if(index == 0)
                continue;

            int days = transactions.get(index).timestamp - prevTimestamp;
            if(days == 0 || days < minDays || days > maxDays) {
               return false;
            }

            prevTimestamp = transactions.get(index).timestamp;
        }

        return true;
    }

    private double getMinimumAmount(List<Transaction> transactions) {
        double minAmount = Double.MAX_VALUE;
        for(Transaction t : transactions) {
            minAmount = Math.min(t.amount, minAmount);
        }

        return minAmount;
    }

    private int getMinimumDays(List<Transaction> transactions) {
        int difference = Integer.MAX_VALUE;
        int prevTimestamp = transactions.get(0).timestamp;
        for(int i=1; i<transactions.size(); i++) {
            difference = Math.min(difference, transactions.get(i).timestamp - prevTimestamp);
            prevTimestamp = transactions.get(i).timestamp;
        }

        return difference;
    }

    public static void main(String[] args) {
        Solution obj = new Solution();

        Transaction[] transactions = new Transaction[] {
                new Transaction("Netflix", 9.99, 10),
                new Transaction("Netflix", 9.99, 20),
                new Transaction("Netflix", 9.99, 30),
                new Transaction("Amazon", 27.12, 32),
                new Transaction("Sprint", 50.11, 45),
                new Transaction("Sprint", 50.11, 55),
                new Transaction("Sprint", 50.11, 65),
                new Transaction("Sprint", 60.13, 77)};

        List<String> result = obj.getCompaniesWithRecurringTransactions(transactions);
        System.out.println("The companies with recurring transactions are: " + result);
    }
}

Round 2

The question is to implement a Central Banking algorithm as defined in the comments.

package random.plaid;

import java.util.*;

/*
 Netting Engine - ACH association
 Minimum number of transfers required at the end of the day based on the net balances of individual banks
 A B C banks -> list of input transfers -> output transfers

    Central Bank Algorithm
    ----------------------

    1. Calc net balance of each bank
    2. Generate one transfer with either send/receive the net amount

STEP 1
    // A, B, amount
    // int[] sendAmts {}
    // int[] receiveAmts {}
    // int[] netbalance {}

STEP 2
    // If the balance is positive, there is transfer from Bank A to Bank i with amount netbalance
    // Else if the balance is negative, there is a transfer from Bank i to Bank A with amount mod(netbalance)

    positive balances
    _ _ _ -> _A_ dest post balance

    negative balance
    _ _ _ -> src _A_ Mod(-neg balance)

Examples:

    Input:
        AB1
        BA2
        ------
        BA1

    Input:
        AB1         A 1   s:2 r:3 -> 1
        BA2 -> BA1  B -2  s:2+1 r:1 -> -2
        BC1 -> BC1  C 1   r:2 -> 2
        AC1         D     s:1 -> -1
        DA1

        Net Balances:
        A: 1  (send 1, receive 2) [receive - send] = net balance
        B: -2 (send 2, receive 1, send 1)
        C: 1  (receive 1)

     Output:
        BA2
        AC2
        DA1

            B,C,D --------> (A) ------->    B,C,D


Input
    B:-2 C:0 D:2

    BC2
    CD2

    B,C,D --------> (A) ------->    B,C,D

Output
    BA2
    AD2

*/

public class Solution {

    static final String CENTRAL_BANK = "A";
    static final int CENTRAL_BANK_ID = 0;

    private List<String> generateMinimumTransfers(List<String> transferDetails) {
        List<String> transfersList = new ArrayList<>();
        if(transferDetails == null || transferDetails.size() == 0) {
            return transfersList;
        }

        int[] sendAmt = new int[26];
        int[] receiveAmt = new int[26];
        int[] netBalance = new int[26];

        for(String t : transferDetails) {
            int srcIdx = t.charAt(0) - 'A';
            int destIdx = t.charAt(1) - 'A';
            int amount = getAmount(t);

            sendAmt[srcIdx] += amount;
            receiveAmt[destIdx] += amount;
        }

        for(int i=0; i<26; i++) {
            if(i == CENTRAL_BANK_ID) {
                continue;
            }

            netBalance[i] = receiveAmt[i] - sendAmt[i];
            if(netBalance[i] > 0) {
                transfersList.add(CENTRAL_BANK + (char)(i + 'A') + netBalance[i]);
            } else if(netBalance[i] < 0) {
                transfersList.add((char)(i + 'A') + CENTRAL_BANK + Math.abs(netBalance[i]));
            }
        }

        return transfersList;
    }

    private int getAmount(String transaction) {
        return Integer.valueOf(transaction.substring(2), 10);
    }

    public static void main(String[] args) {
        Solution obj = new Solution();
        System.out.println();

        System.out.println(obj.generateMinimumTransfers(Arrays.asList("AB1", "BA2")));
        System.out.println(obj.generateMinimumTransfers(Arrays.asList("AB1", "BA2", "BC1")));
        System.out.println(obj.generateMinimumTransfers(Arrays.asList("AB1", "BA2", "BC1", "DA1")));
        System.out.println(obj.generateMinimumTransfers(Arrays.asList("BC1", "CD1")));
        System.out.println(obj.generateMinimumTransfers(Arrays.asList("BC2", "CD1")));
        System.out.println(obj.generateMinimumTransfers(Arrays.asList("BC203", "CD198")));
        System.out.println(obj.generateMinimumTransfers(Arrays.asList("BC2", "CD009")));
    }
}

Looks like question 2 is similar to https://leetcode.com/problems/optimal-account-balancing/

Hope this helps someone!

Comments (9)