Normally, there would be 3 rounds interviews. First round has two questions, first question normally is easy and then the next one could be a bit difficult. Then the second round would be one median level problem and a system / OO design question, or only system / OO design. Final round is either difficult problem or a system / OO design.
Afternoon interviews would be behaviour questions mixed up with the coding, system design and brain teaser problems. I believe the goal of the afternoon interviews would be the decision from team manager, who want to know that you can be the good fit to the team, like solving problems together, discussion and etc.
This document references the posts in 1point3acres and the following docs. Thank you guys.
unary and ternary operators -- add a variable of NumOperands
factory design pattern
Factory design pattern is a class where you can hide the creation logic of all sub-classes. Typically, it would require a type and generate an object of sub-class. Essentially, itโs a mapping from types sub-classes.
structNode { int parentIdx; bool valid; bool visited;Node(int pi) :parentIdx(pi),valid(true),visited(false) {}};classArrayTree { public:ArrayTree(vector nums) { for (int i : nums) { nodes.push_back(newNode(i)); size ++; } }voiddeleteSubtree(int idx) {if (!nodes[idx]->valid) // if already deletedreturn;reset(); // reset valid nodes back to unvisitednodes[idx]->valid =false;nodes[idx]->visited =true; size --;for (int i =0; i <nodes.size(); ++ i) {if (nodes[i]->visited)continue;explore(i); } }private: vector nodes; int size;boolexplore(int idx) { // if current is root or is already visitedif (nodes[idx]->parentIdx ==-1||nodes[idx]->visited) {nodes[idx]->visited =true;returnnodes[idx]->valid; }nodes[idx]->visited =true; // current validness depends on parent validnessbool isParentValid =explore(nodes[idx]->parentIdx);if (nodes[idx]->valid != isParentValid) {nodes[idx]->valid = isParentValid; size --; // only decrement size when change from valid to invalid }return isParentValid; }voidreset() {for (Node * n : nodes) {if (n->valid)n->visited =false; } }};intmain() { vector<int> nums = {1,5,5,2,2,-1,3}; ArrayTree at(nums);at.print();at.deleteSubtree(3);at.print();at.deleteSubtree(6);at.print();at.deleteSubtree(2);at.print();return0;}
Follow Ups
Update tree size
Corner cases
Index is out of range
delete subtree which already removed
Node cannot be changed.
use a boolean array to store the visited indexes.
Round 2 Blocking Queues & Slow Web Diagnose
Question 1: Blocking Queues
Suppose you have two independent blocking queues that will keep getting new data, the new data will always be greater than the last element of the queue it is going to. You can only use getNext() to get the data from these two blocking queues and each data can be fetched only once. Write a program to output all pairs of data from these two blocking queues that have difference smaller than 1.
Because the data comes from two blocking queues, the implementation of
non-streaming version would be two queues and call calculatePairs on different
queue order.
However, becasue the blocking queue could be blocked, because there is no new
incoming data. Thus two threads would be the solution.
C++ code is coyied from somewhere else
Java code is based on the C++ code, and it works.
// this is the final result containing timestamp pairs < 1 vector > result; // queue defined to stored numbers from streams list Q1; // use list so we can iterate list Q2; // the lock shared between threads Lock mutex;// this is a utility function voidcalculate(list&q1,list&q2,double val) {q1.push(val);if (!q2.empty()) {while (!q2.empty() && val -q2.front() >=1) q2.pop(); for (double num : q2) { if (abs(val - num) <1) result.push_back(make_pair(val, num));elsebreak; } }}// function that will be executed by thread 1 voidtask1(Stream s) {while (true) {double val =s.getNext();mutex.lock();calculate(Q1, Q2, val);mutex.unlock(); }}// function that will be executed by thread 2 void task2(Stream s) {while (true) {double val =s.getNext();mutex.lock();calculate(Q2, Q1, val);mutex.unlock(); }}intmain() { // incoming streams Stream S1 = {0.2,1.4,3.0}; Stream S2 = {2.0,2.1,4.5}; // create the threads thread t1(task1, S1); thread t2(task2, S2); // start the threadst1.join();t2.join();}
It should use a list to store the data from each blocking queue.
Lock is the same, it should lock before the calculation and release the lock afterwards.
The thread input should be like (List<List<Double>> queues, int qIndex)
Each thread need to maintain a list of indexes which point to the un-explored position of other queues.
Every time a thread get a new data, start from the current index and find the last index suite the condition of each other queues.
Question 2: Slow Web Accessing
When does it happen? How frequently ?
How slower compare to the normal?
Where does it happen? All places or only several places?
Is there a monitor on the full stack?
Host & service health check
Overall host performance (CPU, Mem, I/O, Disk and etc)
Time of request
Time of back end request
Database response time
Check bandwidth, there are several website to test the bandwidth
Check client device performance (CPU, Mem)
Check DNS, try different ip of the host, Ping the host
Java script issue
Render-blocking, React, life-circle state update
CDN? (content delivery network)
Check the request/response time from Browser Develop Tool. chrome -> develop tools -> network
By checking the develop tool, we could know which request took longest / longer time than normal. So it could give us some evidence / guide to the next step.
Before diving into the backend diagnoses. I have something to say in front. Backend services should have a series of metrics so that the engineer could targeting the problem more easily.
Load Balance
If there was any monitor of the hosts
CPU, Mem, I/O, load
Compare with the historical record, it maybe could give some clue.
Try different request, check whether all request are slow or only some certain ones
Access to the host, check the logs, if there were something like "TraceId" of each request, it would help a lot on find the logs, could just grep it.
It maybe direct the request to one server. If so, it maybe initial design wasn't optimised or need to change the balance strategy.
Backend Services
Monitor is essential.
Overall cluster / hosts performance, CPU, Mem, I/O, Load and etc.
Also disk sometime would cause the problem
Check the service health, if some of the services are down, it could be the reason.
Check request from log by some tracer id
There maybe a loop between services for some certain requests
Tracer Id shows the path of the a request, so it is very useful to diagnosis the problem
Check exceptions from the log, it may cause the problem
Use some command like top on a host.
Enable debug level of the logging, more information, the better.
Message Queue
Not all backend has message queue
Check the lag of topics, maybe there are too many waiting requests on a topic.
Check cluster, like for Kafka, check heath of leader and etc. If leader is down, it maybe struggle on election.
consumer group, like some servers are down.
As backend services, database / cluster should also has the metrics to help the diagnose and monitor the performance
Overall I/O, space, performance
Too many connections
Database is slow
Should design another cache layer between services and database.
Data percentage
Some of the data base performance linked with the consumed space.
Like Cassandra, when it's doing the compaction, it may slow the performance.
Apply retention policy
Some of the nodes in database cluster were down, which raise the internal communications.
Maybe another database cluster and apply sharding.
The solution should start from DP solution. The testing cases should be added at beginning.
Step 1: Recursive Solution
Step 2: DP solution
Step 3: Backtracking
Dp solution and backtrack solution are copied from leetcode
classSolution {publicbooleanisMatch(String s,String p) {int sLen =s.length(), pLen =p.length();// base casesif (p.equals(s) ||p.equals("*")) returntrue;if (p.isEmpty() ||s.isEmpty()) returnfalse;// init all matrix except [0][0] element as Falseboolean[][] d =newboolean[pLen +1][sLen +1]; d[0][0] =true;// DP computefor(int pIdx =1; pIdx < pLen +1; pIdx++) {// the current character in the pattern is '*'if (p.charAt(pIdx -1) =='*') {int sIdx =1;// d[p_idx - 1][s_idx - 1] is a string-pattern match// on the previous step, i.e. one character before.// Find the first idx in string with the previous math.while ((!d[pIdx -1][sIdx -1]) && (sIdx < sLen +1)) sIdx++;// If (string) matches (pattern),// when (string) matches (pattern)* as well d[pIdx][sIdx -1] = d[pIdx -1][sIdx -1];// If (string) matches (pattern),// when (string)(whatever_characters) matches (pattern)* as wellwhile (sIdx < sLen +1) d[pIdx][sIdx++] =true; }// the current character in the pattern is '?'elseif (p.charAt(pIdx -1) =='?') {for(int sIdx =1; sIdx < sLen +1; sIdx++) d[pIdx][sIdx] = d[pIdx -1][sIdx -1]; }// the current character in the pattern is not '*' or '?'else {for(int sIdx =1; sIdx < sLen +1; sIdx++) {// Match is possible if there is a previous match// and current characters are the same d[pIdx][sIdx] = d[pIdx -1][sIdx -1] && (p.charAt(pIdx -1) ==s.charAt(sIdx -1)); } } }return d[pLen][sLen]; }}
classSolution {publicbooleanisMatch(String s,String p) {int sLen =s.length(), pLen =p.length();int sIdx =0, pIdx =0;int starIdx =-1, sTmpIdx =-1;while (sIdx < sLen) {// If the pattern caracter = string character// or pattern character = '?'if (pIdx < pLen && (p.charAt(pIdx) =='?'||p.charAt(pIdx) ==s.charAt(sIdx))){++sIdx;++pIdx; }// If pattern character = '*'elseif (pIdx < pLen &&p.charAt(pIdx) =='*') {// Check the situation// when '*' matches no characters starIdx = pIdx; sTmpIdx = sIdx;++pIdx; }// If pattern character != string character// or pattern is used up// and there was no '*' character in pattern elseif (starIdx ==-1) {returnfalse; }// If pattern character != string character// or pattern is used up// and there was '*' character in pattern beforeelse {// Backtrack: check the situation// when '*' matches one more character pIdx = starIdx +1; sIdx = sTmpIdx +1; sTmpIdx = sIdx; } }// The remaining characters in the pattern should all be '*' charactersfor(int i = pIdx; i < pLen; i++)if (p.charAt(i) !='*') returnfalse;returntrue; }}
The for loop should be trivial.
Bit mask is what interveiwer wanted. It should be explained clearly.
publicbooleanisPowerOfFour(int n) {if (n<=0) returnfalse;while (n %4==0) n/=4;return n ==1;}
// if it will be called lots of times. the good idea would be store the precomputed// results in a map.classPowers {privateint n =15;publicList<Integer> nums =newArrayList();Powers() {int lastNum =1;nums.add(lastNum);for (int i =1; i < n +1; ++i) { lastNum = lastNum *4;nums.add(lastNum); } }}classSolution {publicstaticPowers p =newPowers();publicbooleanisPowerOfFour(int num) {returnp.nums.contains(num); }}
// explain:// 1: the number should also be power of two. // If a number is power of 2, there only one 1 digit in binary number.// So num - 1 will eliminate the last 1, so (num & (num - 1)) == 0// 2: power of 4 means the digit 1 should on the even position (start from 0). // In this way, the bit mask will be like 10101010 -> 1010|2 = 10|10 = a|16public boolean isPowerOfFour(int num) {return num >0&& ((num & (num-1)) ==0) && ((num &0xaaaaaaaa) ==0);}
Question 2: Random Iterator Dividable by 5
Using a random number iterator to crate an iterator that only return multiply of 5
implement next(), hasNext(), remove()
Solution (the question is bit of blur so the solution is based on my understanding)
The class should implement Iterator<Integer>
add nextValue and hasNextValue to the class.
remove the element from the container.
Output numbers only could mod by 5.
Remove some elements from the container
Check again to make sure the elements are removed.
dead cell is born if it has 2 or 3 Y-neighbours alive
living cell survives if it has 2 or 4 Y-neighbours
2D solution
follow up
infinite grid
large grid sparse
distributed system design
* 1D and 2D solution is trivial.
o in place solution would be prefered
o need to ask about the boarder
* Follow ups:
o Infinite grid
o Large grid but alive points are sparse
o Solve it using distribued system
classSolution {publicvoidgameOfLife(int[][] board) {// state:// curr\next | alive | dead// alive | 1 | -1// dead | 2 | 0int row =board.length;if (row ==0) return;int col = board[0].length;if (col ==0) return;for (int i=0;i<row;i++) {for (int j=0;j<col;j++) {int count =0;for (int k =-1; k<=1;k++) {for (int n=-1;n<=1;n++) {if (n ==0&& k ==0) continue;if (i+k >=0&& i+k<row && j+n >=0&& j+n<col) count +=Math.abs(board[i+k][j+n]) ==1?1:0; } }// Rule 1 or Rule 3if ((board[i][j] ==1) && (count <2|| count >3)) {// -1 signifies the cell is now dead but originally was live. board[i][j] =-1; }// Rule 4if (board[i][j] ==0&& count ==3) {// 2 signifies the cell is now live but was originally dead. board[i][j] =2; } } }// Get the final representation for the newly updated board.for (int i =0; i < row; i++) {for (int j =0; j < col; j++) {if (board[i][j] >0) { board[i][j] =1; } else { board[i][j] =0; } } } }}
* Infinite Grid
o Data stracture: Map<Integer, Map<Integer, Integer>> lives
o Better to define a new class to handle the get, put, update and etc
o Infinite Java is the Java version of infinite board
* Sparse Points in very large grid
o It should be the same as above.
* Multi thread / multi process / GPU / distributed system
o Slice the board int to multiple blocks of rowls
o Assign these block / sub maps to each server/thread
. if we use thread, read is safe
o A zookeeper should record the state of each server
o If all servers' state are the same, then start next step
o In order to calculate the elements on boarder, a store layer or server
communicate with each other (ask zookeeper first).
Highlight can be implemented by add another flag in tree node
Two stacks for Redo and Undo
Implement a class of Actions
Stack of Actions
Save & Load
Serialise & Deserialise tree
Search
Boyer-Moore Search
Rope data structure require two operations
1: concat
simplist solution is to create a new node: node.left = root, node.right = inputNode
Need to balance the tree after each concat
2: split
Update root to the left side and return the right side node.
Then the following operations
* Insert(index, str)
o inputNode = new Node(str);
o lastNode = split(index);
o concat(inputNode);
o concat(lastNode);
* Delete(start, end)
o lastNode = split(end)
o deleteNode = split(start)
o concat(lastNode)
* Index(index)
o binary search
* Highlight(start, end)
o lastNode = split(end)
o highlightNode = split(start)
o highlight(highlightNode)
o concat(highlightNode)
o concat(lastNode)
* Search
o Iteriter inorder traverse.
o Boyer-Moore search algorithm.
Solution key points
* DummyHead and DummyTail points to the head and tail of the double linked list
* Apply removeNode and addNode.
o removeNode:
. remove the node from the list, connect its left and right,
o addNode:
. Add the node to the head of the double linked list
* put(key, value)
o check the existence of the key, update the value, update the node.
o check size limit
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > CAPACITY;
}
// Collections wrapper, Most straight farward solution. Less code changeMap<T,T> m =Collections.synchronizedMap(newLinkedHashMap<T,T>(capacity));
Solution key points
* DummyHead and DummyTail points to the head and tail of the double linked list
* Apply removeNode and addNode.
o removeNode:
. remove the node from the list, connect its left and right,
o addNode:
. Add the node to the head of the double linked list
* put(key, value)
o check the existence of the key, update the value, update the node.
o check size limit
Data structure: three maps to keep k-v, k-count, count-list<key> and minCount
* Key-Value map
o Stores the all the key-value
o HashMap<T, T>
* Key-Count map
o Store the count of the key
o HashMap<T, Integer>
* Count-List<Key> map
o Store the list of keys of each count
o HashMap<Integer, LinkedHashSet<T>>
* minCount
o keep track the min count
Testing case should cover:
* ไธคไธชๆฐ็ป้ฝไธบ็ฉบ
* ๆๅ ถไธญไธไธชๆฐ็ปไธบ็ฉบ๏ผๅฆๅคไธไธชๆฐ็ป้ฟๅบฆไธบๅฅๆฐ/ๅถๆฐ
* ๆฐ็ป้ฟๅบฆ้ฝๆฏๅฅๆฐ
* ๆฐ็ป้ฟๅบฆ้ฝๆฏๅถๆฐ
* ๆฐ็ป้ฟๅบฆไธๅฅไธๅถ
* index over the constraint
* overlap & non overlap
private final int[] emptyArray = new int[0];
private final int[] arrayLenOne = new int[]{1};
private final int[] arrayLenTwo = new int[]{1,2};
private final int[] arrayLenTwoLarge = new int[]{8,9};
private final int[] arrayLenTwoDup = new int[]{2,2};
private final int[] arrayLenThree = new int[]{1,2,3};
private final int[] arrayLenThreeLarge = new int[]{7,8,9};
private final int[] arrayLenThreeDup = new int[]{1,3,3};
private final int[] arrayLenMulti = new int[]{1,2,3,4,5,6,7};
private final int[] arrayLenMultiLarge = new int[]{10,11,12,13,14,15};
private final int[] arrayLenMultiDup = new int[]{1,2,2,4,5,5,5};
@Test
public void testEmptyArray() {
Assert.assertEquals(0, findMedianSortedArray(emptyArray, emptyArray));
Assert.assertEquals(1, findMedianSortedArray(emptyArray, arrayLenOne));
Assert.assertEquals(1, findMedianSortedArray(arrayLenOne, emptyArray));
...
}
@Test
public void testEvenOddLengthArray() {
// overlap and non overlap
}
@Test
public void testEvenEvenLengthArray() {
// overlap and non overlap
}
@Test
public void testOddOddLengthArray() {
// overlap and non overlap
}
Round 3 ATM OO design
Design an ATM, some of the basic interfaces are already given, need to add more if necessary and then implement the class.
Because it is a semi open-end question, there is no real correct answer. The following solution is based on my own understanding and above link.
It should use
State Pattern
Mediator Pattern
// Need to implement the following classes
class AccountStore
class CardHandler
class CashDispenser
class CashIntake
// Then there is a menu function in ATM class. Such as
switch (choice) {
case LOGIN:
//TODO: implement function to support user login
}
// ATM class has the following members
AccountStore _accountstore; // store the account created at this ATM
CardHandler _cardhanlder; // handles card read return
CashDispenser _cashdispenser; // handles cash withdraw
CashIntake _cashintake; // handles cash deposit
There are several questions should be asked in front
* output ๆไปไน้ๅถๅ?
Assumption: ๅช่ฝๆฏ20็พๅ ็ๅๆฐ
* Output ไผไธ่ถณๅ?
Assumption: ATMๆฐธ่ฟๆ่ถณๅค็ไฝ้ข (Bonus: ่ฟ้ๅฏไปฅ่่ๅฆๆไธๅค็่ฏๅบ่ฏฅๆไนๅค็)
* Multi Accounts bounded on one card?
* Turn on or off?
* Can we assume there will be no transactions when using ATM
o like if want to withdraw money but at mean time direct debt cut some money
o This is concurrent
* Should message between ATM and Bank encrypt?
// Here I only present the state translate code
public void startServe() {
try {
switch(state) {
case CREATEACCOUNT:
break;
case NOTACTIVE:
char[] accountNum = displayConsole.inputAccountNumber();
if (accountNumberValidation(accountNum)) {
account = cardHandler.getAccount(new String(accountNum));
session = createNewSession();
setState(AtmState.SERVEACCOUNT);
}
break;
case SERVEACCOUNT:
checkSesssion();
// card inserted but not loggedin
if (account != null && !account.isAuthed()) login();
// card insert and account authed
else if (account != null && account.isAuthed()) menu();
// no card, waiting for next serve
else setState(AtmState.NOTACTIVE);
break;
case ERROR:
break;
default:
break;
}
} catch (Exception e) {
log.warning(e.toString());
state = AtmState.ERROR;
}
}
private void login() throws Exception {
for (int i=0;i<5;i++) {
if (account.getAuth(displayConsole.inputPassword())) {
return;
} else {
displayConsole.outputWrongPassword();
}
}
cardHandler.retainCard();
// print something
setState(AtmState.NOTACTIVE);
}
private void menu() throws Exception {
AccountType fromType;
AccountType toType;
float amount;
try {
switch (displayConsole.inputActionSelection()) {
case QUERY:
checkSesssion();
fromType = displayConsole.chooseFromAccount();
account.query(fromType);
break;
case TRANSFER:
do {
checkSesssion();
fromType = displayConsole.chooseFromAccount();
toType = displayConsole.chooseToAccount();
amount = displayConsole.inputAmount();
account.transfer(fromType, toType, amount);
} while (displayConsole.inputNextStep());
break;
case WITHDRAWL:
do {
checkSesssion();
fromType = displayConsole.chooseFromAccount();
amount = displayConsole.inputAmount();
account.withdraw(fromType, amount);
cashExpenserHandler.popCash(amount);
} while (displayConsole.inputNextStep());
break;
case DEPOSIT:
do {
checkSesssion();
toType = displayConsole.chooseToAccount();
amount = displayConsole.inputAmount();
cashEnvelopHandler.countCash(amount);
account.deposit(toType, amount);
} while (displayConsole.inputNextStep());
break;
case LOGOUT:
cardHandler.returnCard();
displayConsole.outputEndMessage();
setState(AtmState.NOTACTIVE);
default:
checkSesssion();
break;
}
} catch (Exception e) {
if (e.getMessage().startsWith("Insufficient Amount")) {
displayConsole.outputInsufficientAmount();
}
}
}
private void setState(AtmState state) {
this.state = state;
startServe();
}
Set 4
The questions in this set are varies. I add all questions whose frequency is higher than the others in this set. Also some of the questions from other set would also be asked in this set.
We need to add locks on each element. It isn't clear what's the data structure. Here is my assumptions
An array to store the count of each element
An map to store the count of each element
Locks :
ReentrantLock
Semaphore: Signal, like limit the number of the thread
Mutex:
Possible solutions
* It is a producer - consumer model
* Lock
o Some mates said about mutex, semaphore, sychronization and ReeentrantLock
* The code is based on my search and understanding. I left the eggLock to demo
that when there is no lock, it may be error message.
Because currently they are all virtual interviews. This problem may not be asked.
It should use pull and push model.
Pull model for the personal websites, like fackbook or twitter
Push model for the general websites, like wsj or nytimes
* Feed system
* Web crawler
* Search
Average: maintain a total sum, average = sum / stack size
Min: use a stack to store min
Max: use a stack to store max
mode: Like LFU cache, but keep the max instead of min.
Median: Two queues and a map to track the removed ones
Here I only implements the average, min, max and mode.
Because mode is quite complex so I create another class to handle it.
It would be better to design the unit test.
class Mode {
private Map<Integer, Integer> valueCount;
private Map<Integer, LinkedHashSet<Integer>> countList;
private int max;
public Mode() {
valueCount = new HashMap<>();
countList = new HashMap<>();
max = 0;
}
public void put(int val) {
if (valueCount.containsKey(val)) {
int count = valueCount.get(val);
valueCount.put(val, count + 1);
countList.get(count).remove(val);
if (countList.get(count).isEmpty()) countList.remove(count);
countList.computeIfAbsent(count + 1, x -> new LinkedHashSet<>())
.add(val);
if (max == count) max++;
} else {
valueCount.put(val, 1);
if (max == 0) max++;
countList.computeIfAbsent(1, x -> new LinkedHashSet<>()).add(val);
}
}
public void remove(int val) {
if (valueCount.containsKey(val)) {
int count = valueCount.get(val);
if (count-1 == 0) {
valueCount.remove(val);
} else {
valueCount.put(val, count-1);
}
countList.get(count).remove(val);
if (count == max && countList.get(count).isEmpty()) max--;
if (countList.get(count).isEmpty()) countList.remove(count);
countList.computeIfAbsent(count - 1, x -> new LinkedHashSet<>())
.add(val);
}
}
/**
* @return oldest most frequent element in the stack
* @throws Exception
*/
public int getMostFrequentValue() throws Exception {
if (valueCount.isEmpty())
throw new NoSuchElementException("Stack is empty.");
return countList.get(max).iterator().next();
}
}
class SuperStack {
private long sum;
private Stack<Integer> stack;
private Stack<Integer> minStack;
private Stack<Integer> maxStack;
private Mode mode;
public SuperStack() {
sum = 0;
stack = new Stack<>();
minStack = new Stack<>();
maxStack = new Stack<>();
mode = new Mode();
}
public void push(int val) {
stack.push(val);
sum += val;
if (minStack.empty() || minStack.peek() >= val) minStack.push(val);
if (maxStack.empty() || maxStack.peek() <= val) maxStack.push(val);
mode.put(val);
}
public int peek() throws EmptyStackException {
return stack.peek();
}
public void pop() throws EmptyStackException {
int val = stack.pop();
sum -= val;
if (val == minStack.peek()) minStack.pop();
if (val == maxStack.peek()) maxStack.pop();
mode.remove(val);
}
public int min() throws EmptyStackException {
return minStack.peek();
}
public int max() throws EmptyStackException {
return maxStack.peek();
}
public double average() throws EmptyStackException {
if (stack.empty()) throw new EmptyStackException();
return (double)sum / stack.size();
}
public int mostFrequentValue() throws Exception {
return mode.getMostFrequentValue();
}
}
1: test exceptions
2: test stack pop, push and peek
3: test min & max stack
4: test average
5: test mode
a: push
b: remove
c: getMostFrequentValue
Question 2 String multiply
Leetcode 43:
Key points
multiply a string to a digit
Remember to add tailing zeros
add two strings
* multiply a string and a digit
* add two strings
* loop on shorter string and skip zeros
* better to use StreamBuilder
class Solution {
public String multiply(String num1, String num2) {
int len1 = num1.length();
int len2 = num2.length();
if (len1 == 0 || len2 == 0) {
return num1 + num2;
}
if (num1.equals("0") || num2.equals("0")) {
return "0";
}
String res = "0";
for (int i=len1-1;i>=0;i--) {
int n = num1.charAt(i) - '0';
if (n == 0) continue;
String oneMultiple = multipleOneDigit(num2, n, len1-i-1);
res = addString(oneMultiple, res);
}
return res;
}
private String multipleOneDigit(String num, int n, int tailingZeros) {
char[] charArray = num.toCharArray();
int len = charArray.length;
int carry = 0;
String res = "";
for (int i=len-1;i>=0;i--) {
int c = charArray[i] - '0';
int curr = c * n + carry;
res = Integer.toString(curr%10) + res;
carry = curr/10;
}
res = carry > 0 ? Integer.toString(carry) + res : res;
while(tailingZeros > 0 ) {
res+="0";
tailingZeros--;
}
return res;
}
private String addString(String n1, String n2) {
int len1 = n1.length();
int len2 = n2.length();
if (len1 == 0 || len2 == 0) {
return n1 + n2;
}
int carry = 0;
String res = "";
while (len1>0 && len2>0) {
int d1 = n1.charAt(--len1) - '0';
int d2 = n2.charAt(--len2) - '0';
int sum = d1 + d2 + carry;
res = Integer.toString(sum%10) + res;
carry = sum/10;
}
while (len1>0) {
int d1 = n1.charAt(--len1) - '0';
int sum = d1 + carry;
res = Integer.toString(sum%10) + res;
carry = sum/10;
}
while (len2>0) {
int d2 = n2.charAt(--len2) - '0';
int sum = d2 + carry;
res = Integer.toString(sum%10) + res;
carry = sum/10;
}
if (carry>0) {
res = Integer.toString(carry) + res;
}
return res;
}
}
Weighted samplingใ็ปไธไธชarray of tuple็๏ผweight, data๏ผ๏ผ่ฆๆฑไปฅ็ปๅฎ็ๆฆ็sampleๆฐๆฎใ ๆไผ็ญๆกๆฏbinary indexd tree log(n)็่ฏปๅcomplexity๏ผ่ไธๆฏๆinsert/delete๏ผ้ฝๆฏlog(n) ๆ็ปๅบๆฎ้็ญๆก๏ผ่ฎฐไฝๅทฒๆ็weight็ถๅๆฅๆพใ้ข่ฏๅฎไน่ฎคๅฏไบใ
* Game
o Game class should have a board and some player
o it should control when start and end
* Board
o Board should record the players location.
o interfaces:
. registerPlayer(Player)
. int isCloser(Player, Move)
* Player
o Player should only record the result from prev move, for decision
o interfaces:
. int[] nextMove();
. setResult(int)
public interface IPlayer {
public int[] nextMove();
public void setResult(int isCloser);
}
public class RandomPlayer implements IPlayer {
public RandomPlayer() {}
public int[] nextMove() {
int[] nextMove = new int[2];
int index = Math.random() >= 0.5 ? 0 : 1;
nextMove[index] = Math.random() >= 0.5 ? -1 : 1;
return nextMove;
}
public void setResult(int _result) {
}
}
public class SmartPlayer implements Player {
private int result;
private boolean isPrevBad;
private int[] move;
public SmartPlayer() {
result = -2;
move = new int[2];
isPrevBad = false;
}
public int[] nextMove() {
if (result == -2) {
move[1] = 1;
} else {
if (result == 0) {
move[0] = 0;
move[1] = 0;
isPrevBad = false;
} else if (result == 1) {
if (isPrevBad) {
int x = move[0] == 0 ? (move[1] == 1 ? 1 : -1) : 0;
int y = move[1] == 0 ? (move[0] == 1 ? -1 : 1) : 0;
move[0] = x;
move[1] = y;
isPrevBad = false;
}
} else {
move[0] = move[0] == 0 ? 0 : (-1 * move[0]);
move[1] = move[1] == 0 ? 0 : (-1 * move[1]);
isPrevBad = true;
}
}
return move;
}
public void setResult(int result) {
this.result = result;
}
}
public interface IBoard {
public void registerPlayer(Player player);
public int isCloser(Player player, int[] move);
}
public class Board implements IBoard {
private Map<Player, int[]> players;
private int[] target;
private int limit;
public Board(int[] target, int limit) {
this.target = target;
this.limit = limit;
players = new HashMap<>();
}
public void registerPlayer(Player player) {
if (!players.containsKey(player)) {
int[] location = new int[]{(int)(Math.random()*limit) ,
(int)(Math.random()*limit)};
players.put(player, location);
}
}
public int isCloser(Player player, int[] move) {
int[] prev = players.get(player);
int x = move[0];
int y = move[1];
int[] curr = new int[]{prev[0] + x, prev[1]+y};
players.put(player, curr);
int diff = distance(curr) - distance(prev);
return diff < 0 ? 1 : (diff == 0 ? 0 : -1);
}
public void print() {
for (Map.Entry<Player, int[]> entry : players.entrySet()) {
System.out.println(String.format("Player %s position %d %d",
entry.getKey().toString(),
entry.getValue()[0],
entry.getValue()[1]));
}
}
private int distance(int[] curr) {
return (curr[0]-target[0])*(curr[0]-target[0]) +
(curr[1]-target[1])*(curr[1]-target[1]);
}
}
class PlayerFactory {
public PlayerFactory() {
}
public Player getPlayer(PlayerType type) {
if (type == PlayerType.SMART) return new SmartPlayer();
else return new RandomPlayer();
}
}
enum PlayerType {
SMART,
RANDOM
}
class Game {
private Board board;
private Set<Player> players;
private PlayerFactory playerFactory;
private int totalSteps;
public Game(Board board, int totalSteps) {
this.board = board;
this.totalSteps = totalSteps;
playerFactory = new PlayerFactory();
players = new HashSet<>();
}
public void addPlayers(PlayerType type) {
Player player = playerFactory.getPlayer(type);
players.add(player);
board.registerPlayer(player);
}
public void start() {
for (int i=0;i<totalSteps;i++) {
for (Player player : players) {
int[] playerNextMove = player.nextMove();
int result = board.isCloser(player, playerNextMove);
player.setResult(result);
}
board.print();
}
}
}
public class GameImpl {
public static void main(String[] args) {
Board board = new Board(new int[]{0,0}, 10);
Game game = new Game(board, 20);
game.addPlayers(PlayerType.SMART);
game.addPlayers(PlayerType.RANDOM);
game.addPlayers(PlayerType.RANDOM);
game.start();
board.print();
}
}
Stock subscription notification system
It should be like the message queue subscription model.
ๆๅคงๆฆๆ่ไบไธไธไนฑ่ฏดไบไธไธชheadโฆโฆๅๆฅwork out math็ๆถๅๆๅ็ฐheadๅtail็ๆถ้ดๆฏ็ธๅ็๏ผๆๅฐฑๅผๅง่งๅพๅบ่ฏฅๆฏmidwayๅ็็ๆถ้ดๆ้ฟ๏ผ(่ฟไธชๆถๅๆไธไธชๅ่ฎพๆฏๅ้ๅๅ ้็ๅ ้ๅบฆๆฏ็ธๅ็)ใ
้ข่ฏๅฎ่ฏดๅฏน๏ผ็ถๅๅฐฑ้ฎhow much longer? ็ถๅ็ปไบไธไธชๆ็คบ็จs = 1/2 a t t่ฟไธชๅ ฌๅผๅปๆจ๏ผๆๅคงๆฆๅไบๅ ่ก่ทไป่ฏดๅคงๆฆๆฏ(sqrt{2} - 1) longer๏ผไปๆ็นๆ่ฎถๅ ไธบไปๅฅฝๅ่งๅพๆๅพๅคๆญฅ้ชค่ทณๆไบโฆโฆanywayไป่งๅพๆฒก้ฎ้ข๏ผๅๆฅๅ้ฎๅฆๆๅ้ๅๅ ้็ๅ ้ๅบฆไธๅ้ฃๆไนๅ๏ผๅชไธช็นๅ็็ๆถ้ดๆ้ฟ๏ผๆ็ดๆฅ็ปไบไธคไธ็ไบไธไธช่กจ่พพๅผๅคงๆฆๅฐฑ่ฏดๆฏ่ฆๅจ่ฝฆ็(a2 / (a1 + a2))ๅ็็ๅฐๆนโฆโฆ้ข่ฏๅฎๅฐฑ้ฎไธบๅฅ๏ผๆๅฐ่ฏwork out mathไบๅๅคฉๆชๆ๏ผๅๆญฃๅคงๆฆๅฐฑๆฏ1/2 a1 t1 t1 = x, 1/2 a2 t2 *t2 = S - x็ถๅๅปmaximize t1 + t2็ๅผ๏ผๅพๆๆพ็ๆ็ๆฐๅญฆๆฐดๅนณๅทฒ็ถไธ่ถณไปฅ่งฃๅณ่ฟไธช้ฎ้ขไบโฆโฆ