# Phone Screen @Box

Position: Software Engineer, Full Stack/Developer Experience

1. Introduce what they are working on
2. Technical Questions
1. Merge two sorted array: just describe the algorithm and time complexity
2. Merge K sorted array: write the code.
3. Two Sum: an sorted array, find if there is at least a pair of two elements which the sum equals 0. Just describe the algorithm and time complexity.
I gave him two approaches: using HashMap and two pointers.
Then he asked me to write the code with two pointers.
4. Three Sum: just describe the algorithm and time complexity.
Share

# How would I design the elevators for a new 40 story office

building that had an average of 100 people per floor to most efficiently fill and empty the building given a standard 9-5 workday and traffic conditions in my city? The answer needed to be completely detailed, including expected passengers per car, time per stop, average floors stops per trip at various hours, etc.

1. How many elevators are there?
2. What is the capacity of each elevator?
3. Is the efficiency goal focused only at the start & end of day & not in between (i.e. lunch time, breaks)?

2. General optimal critiera

• provide even service to each floor
• minimize how long passengers wait for an elevator to arrive
• minimize how long passengers spend to get to their destination floor
• serve as many passengers as possible

The first advice that I’ve read is to ask some questions before you start answering. It will show that you are strategic & don’t jump to random assumptions. So I will probably ask questions like: Is the efficiency goal focused only at the start & end of day & not in between (i.e. lunch time, breaks)? How many elevators are there? What is the capacity of each elevator?

2) Assuming that everything is average, i.e. 6 elevators, 15 people per elevator, and focus only on start and end date, then the sample data should follow a normal distribution.

730-8 – 2%

8-830 – 14%

830-9 – 34%

9-930 – 34%

930-10 – 14%

10-1030 – 2%

3) I will break this down & solve the worst case scenario first. This means, 34 people x 40 floors = 1360 people to be transported by 6 elevator x 15 = total 90 capacity during 830-9 or 9-930 am.

4) Focusing on this more manageable problem, 1360 / 90 means each elevator will make 15 full cycles (lobby to highest floor and back) 5) Since we want to minimize the cycle time for each elevator, we assign one elevator per subset of 40/6 consecutive floors. This should address the issue on minimizing time per stop. 6) That means, the final design should be a load balancing of the elevators by minimizing the travel time — Elevator A – 1st to 7th floor, B – 8th to 14th floor, and so forth. Do you guys see anything wrong with this line of thinking?

1 Elevator Object, 应该包含physical components: Door, Indicator Lights,
Control Panel. 一些性质(Non physical properties): Speed, Num of floors,
capacity, max weight. 所能从事的操作methods: moveto, stop, ringbell。然后电

requestHandler(Strategy pattern),可以set不同的requestHanlder.

2 Door, properties: State, method: open, close， getState.

3 Indicator light(指示所到楼层），properties: state; method: on, off,
getState

4 Control Panel, 包含physical component: Floor Buttons, Other buttons(也可直

5 Button, properties: floorNum, Parent Elevator, methods: OnPress(Observer
Pattern).

6 ElevatorRequestHandler: handleRequest(Elevator ele, requestList rlist), 可

7 Request: 可以define 一个abstract class, 然后有子类movingRequest,
helpRequest doorRequest etc.

### A Single Elevator

Use Case:

1. User
1. press a button to summon the lift
2. press a button to get to a specific floor
2. Button
1. floor button and level button
2. illuminates when pressed
3. place an ‘elevator request’ when pressed
3. Elevator
1. moves up/down
2. open/close the door

ElevatorRequests Class

Each button press results in an elevator request which has to be served. Each of these requests is tracked at a global place. ElevatorRequests, the class which stores elevator requests can use different strategies to schedule the elevator requests.

ElevatorController

The elevator is controlled by a controller class which we call ElevatorController. The elevator controller instructs the elevator what to do and also can shutdown/start up the elevator of the building. The elevator controller reads the next elevator request to be processed and serves it.

Button (Abstract) Class

Button is abstract class defining common behavior like illuminate, doNotIlluminate. FloorButton, ElevatorButton extend Button type and define placeRequest() which is invoked when the button is pressed.

In conclusion, ElevatorController runs the show by reading the ElevatorRequests to process and instructing the Elevator what to do. User send request by pressing Buttons.

### Extend the answer to multiple elevators

1. Each elevator have 1 controller.
2. Floor based requests can be served by any elevator, thus these requests are added to a common area accessible by all controllers.
3. Each elevator controller runs as a separate thread and checks if it can process a floor request. Mind synchronization issues.

http://www.columbia.edu/~cs2035/courses/ieor4405.S13/p14.pdf

https://github.com/joeblau/sample-elevator-control-system

http://blog.jobbole.com/74672/

http://blog.gssxgss.me/elevator-simulator-java/

# Count Univalue Subtrees

Count Univalue Subtrees

Given a binary tree, count the number of uni-value subtrees.

A Uni-value subtree means all nodes of the subtree have the same value.

For example:
Given binary tree,

```              5
/ \
1   5
/ \   \
5   5   5
```

return `4`.

Solution:

```public int countUnivalSubtrees(TreeNode root) {
int[] count = new int[1];
isUnivalSubtrees(root, count);
return count[0];
}

public boolean isUnivalSubtrees(TreeNode root, int[] count) {
if (root == null) {
return false;
}
boolean left = isUnivalSubtrees(root.left, count);
boolean right = isUnivalSubtrees(root.right, count);
if (!left && !right) {
if (root.left == null && root.right == null) {
count[0]++;
return true;
}
} else if (left && right) {
if (root.left.val == root.val && root.right.val == root.val) {
count[0]++;
return true;
}
} else if (left && !right) {
if (root.right == null && root.left.val == root.val) {
count[0]++;
return true;
}
} else if (!left && right) {
if (root.left == null && root.right.val == root.val) {
count[0]++;
return true;
}
}
return false;
}```

# Ugly Number I & II

Ugly Number I

Write a program to check whether a given number is an ugly number.

Ugly numbers are positive numbers whose prime factors only include `2, 3, 5`. For example, `6, 8` are ugly while `14` is not ugly since it includes another prime factor `7`.

Note that `1` is typically treated as an ugly number.

```public boolean isUgly(int num) {
if (num <= 0) {
return false;
}
if (num == 1) {
return true;
}
int[] factors = {2, 3, 5};
for (int i = 0; i < factors.length; i++) {
while (num % factors[i] == 0) {
num = num / factors[i];
}
}
return num == 1;
}```

Ugly Number II

Write a program to find the `n`-th ugly number.

Ugly numbers are positive numbers whose prime factors only include `2, 3, 5`. For example, `1, 2, 3, 4, 5, 6, 8, 9, 10, 12` is the sequence of the first `10` ugly numbers.

Note that `1` is typically treated as an ugly number.

https://leetcode.com/discuss/52716/o-n-java-solution

Solution:

O(n) time, one pass solution. O(n) space.

The ugly-number sequence is 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, … because every number can only be divided by 2, 3, 5, one way to look at the sequence is to split the sequence to three groups as below:

```(1) 1×2, 2×2, 3×2, 4×2, 5×2, …
(2) 1×3, 2×3, 3×3, 4×3, 5×3, …
(3) 1×5, 2×5, 3×5, 4×5, 5×5, …```

We can find that every subsequence is the ugly-sequence itself (1, 2, 3, 4, 5, …) multiply 2, 3, 5.

Then we use similar merge method as merge sort, to get every ugly number from the three subsequence.

Every step we choose the smallest one, and move one step after,including nums with same value.

```    public int nthUglyNumber(int n) {
int[] ugly = new int[n];
ugly[0] = 1;
int index2 = 0, index3 = 0, index5 = 0;
int factor2 = 2, factor3 = 3, factor5 = 5;
for (int i = 1; i < n; i++) {
int min = Math.min(Math.min(factor2, factor3), factor5);
ugly[i] = min;
if (factor2 == min) {
index2++;
factor2 = 2 * ugly[index2];
}
if (factor3 == min) {
index3++;
factor3 = 3 * ugly[index3];
}
if (factor5 == min) {
index5++;
factor5 = 5 * ugly[index5];
}
}
return ugly[n - 1];
}```

# Union-Find 并查集

Union-Find is an algorithm which is widely used to solve finding disjoint components.

```void init(int[] nums) {
int[] fathers = new int[nums.length];
//initially, father is itself
for (int i = 0; i < nums; i++) {
fathers[i] = i;
}
}

//find the father for both nodes
//if they are in different groups, union them by setting fathers[xFather] = yFather;
void union(int x, int y, int[] fathers) {
int xFather = findAndSet(x, fathers);
int yFather = findAndSet(y, fathers);
fathers[xFather] = yFather;
}

//recursively find its parent until reach the top which its parent is itself
//to improve the performance, we compress the path by setting the top father
//so that next time we call find, it is O(1) time complexity
int findAndSet(int x, int[] fathers) {
int parent = fathers[x];
while (parent != fathers[parent]) {
parent = fathers[parent];
}
return parent;
}```

Related Questions:

1. Graph Valid Tree Medium

Given `n` nodes labeled from `0` to `n - 1` and a list of undirected edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree.

For example:

Given `n = 5` and `edges = [[0, 1], [0, 2], [0, 3], [1, 4]]`, return `true`.

Given `n = 5` and `edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]]`, return `false`.

Note: you can assume that no duplicate edges will appear in `edges`. Since all edges are undirected, `[0, 1]` is the same as `[1, 0]` and thus will not appear together in `edges`.

```//union-find algorithm
//findSet is a faster version of find method which finds the top father of a node
//and then set the father to
//which basically compress the path.
//another improvement could be: only
public boolean validTree(int n, int[][] edges) {
int[] fathers = new int[n];
for (int i = 0; i < n; i++) {
fathers[i] = i;
}
for (int i = 0; i < edges.length; i++) {
//union
int xfather = findSet(edges[i][0], fathers);
int yfather = findSet(edges[i][1], fathers);
//since there is no duplicate edge(important! otherwise this algorithm is wrong)
//so if xfather == yfather means they are in
if (xfather == yfather) {
return false;
}
fathers[xfather] = yfather;
}
//there should only be one node(root) pointing to itself
int count = 0;
for (int i = 0; i < fathers.length; i++) {
if (fathers[i] == i) {
count++;
}
}
return count == 1;
}

public int findSet(int x, int[] fathers) {
int parent = fathers[x];
while (parent != fathers[parent]) {
parent = fathers[parent];
}
fathers[x] = parent;
return parent;
}```
```public List<List<Integer>> connectedSet(ArrayList<UndirectedGraphNode> nodes) {
//init unions
Map<Integer, Integer> fathers = new HashMap<>();
for (UndirectedGraphNode node : nodes) {
int label = node.label;
if (!fathers.containsKey(label)) {
fathers.put(label, label);
}
for (UndirectedGraphNode neighbor : node.neighbors) {
union(label, neighbor.label, fathers);
}
}
//put it into a new map which key is the father of the component
//value is a list of node within the component
Map<Integer, List<Integer>> components = new HashMap<>();
for (Integer label : fathers.keySet()) {
int father = findAndSet(label, fathers);
if (components.containsKey(father)) {
} else {
List<Integer> component = new ArrayList<>();
components.put(father, component);
}
}
//sort the result
List<List<Integer>> res = new ArrayList<>();
for (List<Integer> component : components.values()) {
Collections.sort(component);
}
return res;
}

public void union(int x, int y, Map<Integer, Integer> fathers) {
int xFather = findAndSet(x, fathers);
int yFather = findAndSet(y, fathers);
if (xFather != yFather) {
fathers.put(xFather, yFather);
}
}

public int findAndSet(int label, Map<Integer, Integer> fathers) {
if (!fathers.containsKey(label)) {
fathers.put(label, label);
return label;
}
int parent = fathers.get(label);
while (parent != fathers.get(parent)) {
parent = fathers.get(parent);
}
fathers.put(label, parent);
return parent;
}```
```public List<List<Integer>> connectedSet2(ArrayList<DirectedGraphNode> nodes) {
//init unions
Map<Integer, Integer> fathers = new HashMap<>();
for (DirectedGraphNode node : nodes) {
int label = node.label;
if (!fathers.containsKey(label)) {
fathers.put(label, label);
}
for (DirectedGraphNode neighbor : node.neighbors) {
union(label, neighbor.label, fathers);
}
}
//put it into a new map which key is the father of the component
//value is a list of node within the component
Map<Integer, List<Integer>> components = new HashMap<>();
for (Integer label : fathers.keySet()) {
int father = findAndSet(label, fathers);
if (components.containsKey(father)) {
} else {
List<Integer> component = new ArrayList<>();
components.put(father, component);
}
}
//sort the result
List<List<Integer>> res = new ArrayList<>();
for (List<Integer> component : components.values()) {
Collections.sort(component);
}

return res;
}

public void union(int x, int y, Map<Integer, Integer> fathers) {
int xFather = findAndSet(x, fathers);
int yFather = findAndSet(y, fathers);
if (xFather != yFather) {
fathers.put(xFather, yFather);
}
}

public int findAndSet(int label, Map<Integer, Integer> fathers) {
if (!fathers.containsKey(label)) {
fathers.put(label, label);
return label;
}
int parent = fathers.get(label);
while (parent != fathers.get(parent)) {
parent = fathers.get(parent);
}
fathers.put(label, parent);
return parent;
}```

# Find Connected Components in Directed/Undirected Graph

Undirected Graph

1. BFS

2. Union Find

Directed Graph

1. Tarjan

https://www.byvoid.com/blog/scc-tarjan

# Partition Array

1. with target outside the array

```    public int partitionArray(int[] nums, int k) {
if (nums == null || nums.length == 0) {
return 0;
}
int left = 0;
int right = nums.length - 1;
while (left <= right) {
while (left <= right && nums[left] < k) {
left++;
}
while (left <= right && nums[right] >= k) {
right--;
}
if (left < right) {
swap(nums, left, right);
left++;
right--;
}
}
return left;
}

public void swap(int[] nums, int a, int b) {
int tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
}```

2. with target with in the array(Quick select)