Skip to content

Commit 99c8e40

Browse files
committedJul 16, 2023
✨ [msi-global]
1 parent b0b5724 commit 99c8e40

File tree

3 files changed

+360
-0
lines changed

3 files changed

+360
-0
lines changed
 

‎pre_interview/flintex/ShortestPath JAVA.TXT

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import java.util.ArrayList;import java.util.List;public class Company { // IMPORTANT: DO NOT MODIFY THIS CLASS public static class Employee { private final int id; private final String name; private List<Employee> reports; public Employee(int id, String name) { this.id = id; this.name = name; this.reports = new ArrayList<Employee>(); } public int getId() { return id; } public String getName() { return name; } public List<Employee> getReports() { return reports; } public void addReport(Employee employee) { reports.add(employee); } } /* * Read the attached PDF for more explanation about the problem * Note: Don't modify the signature of this function * @param ceo * * @param firstEmployee * * @param secondEmployee * * @return the shortest path from First Employee to the Second Employee. */ @SuppressWarnings("unused") public static String shortestPath(Employee ceo, Employee firstEmployee, Employee secondEmployee) { // Implement me return null; } public static void main(String[] args) { Employee Eugene = new Employee(1, "Eugene"); Employee Jose = new Employee(2, "Jose"); Employee Kelvin = new Employee(3, "Kelvin"); Employee Terence = new Employee(4, "Terence"); Employee Dennis = new Employee(5, "Dennis"); Employee Eunice = new Employee(6, "Eunice"); Employee Bryan = new Employee(7, "Bryan"); Employee Gabriel = new Employee(8, "Gabriel"); Employee Jimmy = new Employee(9,"Jimmy"); Eugene.addReport(Jose); Eugene.addReport(Kelvin); Eugene.addReport(Terence); Jose.addReport(Dennis); Jose.addReport(Eunice); Jose.addReport(Bryan); Eunice.addReport(Gabriel); Eunice.addReport(Jimmy); //pls add other test cases to fully cover different scenarios. System.out.println(shortestPath(Eugene, Gabriel, Jimmy)); }};

‎pre_interview/flintex/my_solution.txt

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package shortestPath;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.HashMap;
7+
import java.util.HashSet;
8+
import java.util.Queue;
9+
import java.util.LinkedList;
10+
import java.util.Set;
11+
12+
public class Company {
13+
14+
// IMPORTANT: DO NOT MODIFY THIS CLASS
15+
public static class Employee {
16+
17+
private final int id;
18+
private final String name;
19+
private List<Employee> reports;
20+
21+
public Employee(int id, String name) {
22+
this.id = id;
23+
this.name = name;
24+
this.reports = new ArrayList<Employee>();
25+
}
26+
27+
public int getId() {
28+
return id;
29+
}
30+
31+
public String getName() {
32+
return name;
33+
}
34+
35+
public List<Employee> getReports() {
36+
return reports;
37+
}
38+
39+
public void addReport(Employee employee) {
40+
reports.add(employee);
41+
}
42+
}
43+
44+
/*
45+
* Read the attached PDF for more explanation about the problem
46+
* Note: Don't modify the signature of this function
47+
* @param ceo
48+
*
49+
* @param firstEmployee - starting node
50+
*
51+
* @param secondEmployee - destination node
52+
*
53+
* @return the shortest path from First Employee to the Second Employee. Separated by " > " and return null if not found.
54+
*/
55+
@SuppressWarnings("unused")
56+
public static String shortestPath(Employee ceo, Employee firstEmployee, Employee secondEmployee) { // The time complexity: O(v + e); space complexity is: O(v + e)
57+
/*
58+
* My thought process:
59+
* when i see the word "shortest path", the first thing that comes into my mind is Djikstra's algorithm, but this is just simply hierarchical structure without distance/priority. This can be viewed as an undirected graph problem that each employee is a node, and reporting relationship forms the edges. (connectivity)
60+
*
61+
* A few assumptions:
62+
* - the ceo, first and second employees always exists in the organisation (graph) - otherwise not found case would be needed
63+
* - its an undirected graph as it is a hierarchical layout we do not need to handle cyclical behaviour
64+
* - there is no self report such as Bryan manages Bryan - my handling is just returning it's path which is the employee name when the same guy is entered for both 1st and 2nd employee
65+
* - edge cases like: no relationship between two employees under the CEO, we can just simply return null
66+
*
67+
*/
68+
69+
Map<Employee, List<Employee>> graph = new HashMap<>(); // adjacency list
70+
71+
// space: O(v)
72+
Set<Employee> visited = new HashSet<>();
73+
74+
// space: O(v)
75+
Queue<Employee> queue = new LinkedList<>(); // LinkedList is more efficient for BFS as ArrayList's removal is O(n); LinkedList is O(1) - as we are not accessing any of the elements at specific index (ArrayList) which costs O(n), so it's better to use a LinkedList.
76+
77+
// space: O(v)
78+
Map<Employee, Employee> prev = new HashMap<>(); // for tracing back the shortest path when we find that 1st == 2nd
79+
80+
// building the graph (adjacency list to store relationships btw employees)
81+
// time: O(v + e) - v: vertices, e: edges; space: O(v + e)
82+
addToGraph(graph, ceo);
83+
System.out.println(graph);
84+
85+
queue.add(firstEmployee);
86+
87+
// BFS - to find SP btw 2 nodes
88+
// time: O(v + e)
89+
while (!queue.isEmpty()) {
90+
Employee current = queue.poll();
91+
visited.add(current); // visit the node
92+
93+
if (current.equals(secondEmployee)) {
94+
StringBuilder path = new StringBuilder(); // build and return the path from 1st to 2nd employee
95+
96+
while (current != null) {
97+
if (!path.isEmpty()) {
98+
path.insert(0, " > "); // prepend a " > " before appending the name ONLY when it is not empty.
99+
}
100+
path.insert(0, current.getName()); // prepend name before the path
101+
current = prev.get(current); // get the next guy
102+
}
103+
104+
return path.toString();
105+
}
106+
107+
// exit (continue) early if not found in the adjacency list (graph)
108+
if (!graph.containsKey(current)) {
109+
continue;
110+
}
111+
112+
// Find the connection(s)
113+
// 0 - Gabriel -> G => [E];
114+
// 1 - Eunice -> E => [J, G, J]; // Jimmy is one of them. - later the cond above should match and return
115+
// in short, prev is more of like the previous visited lookup map, if we can find the 1st == 2nd employees, we can simply look back up to form the path, like:
116+
// e.g. Gabriel to fnd Jimmy
117+
// - the final map: {Eugene=Jose, Dennis=Jose, Eunice=Gabriel, Jose=Eunice, Jimmy=Eunice, Bryan=Jose}
118+
// when we find Jimmy, we can look back up from Jimmy -> Eunice -> Gabriel
119+
for (Employee next : graph.get(current)) {
120+
if (!visited.contains(next)) {
121+
queue.add(next);
122+
prev.put(next, current);
123+
}
124+
}
125+
}
126+
127+
return null; // There is no path between firstEmployee and secondEmployee
128+
}
129+
130+
// Helper function to add relationships to the graph
131+
private static void addToGraph(Map<Employee, List<Employee>> graph, Employee employee) {
132+
if (!graph.containsKey(employee)) {
133+
graph.put(employee, new ArrayList<>());
134+
}
135+
136+
for (Employee report : employee.getReports()) {
137+
if (!graph.containsKey(report)) {
138+
graph.put(report, new ArrayList<>());
139+
}
140+
141+
graph.get(employee).add(report);
142+
graph.get(report).add(employee);
143+
addToGraph(graph, report);
144+
}
145+
}
146+
147+
public static void main(String[] args) {
148+
Employee Eugene = new Employee(1, "Eugene");
149+
Employee Jose = new Employee(2, "Jose");
150+
Employee Kelvin = new Employee(3, "Kelvin");
151+
Employee Terence = new Employee(4, "Terence");
152+
Employee Dennis = new Employee(5, "Dennis");
153+
Employee Eunice = new Employee(6, "Eunice");
154+
Employee Bryan = new Employee(7, "Bryan");
155+
Employee Gabriel = new Employee(8, "Gabriel");
156+
Employee Jimmy = new Employee(9, "Jimmy");
157+
158+
Eugene.addReport(Jose);
159+
Eugene.addReport(Kelvin);
160+
Eugene.addReport(Terence);
161+
162+
Jose.addReport(Dennis);
163+
Jose.addReport(Eunice);
164+
Jose.addReport(Bryan);
165+
166+
Eunice.addReport(Gabriel);
167+
Eunice.addReport(Jimmy);
168+
169+
// Test cases
170+
System.out.println(shortestPath(Eugene, Gabriel, Jimmy)); // Gabriel > Eunice > Jimmy
171+
System.out.println(shortestPath(Eugene, Jimmy, Bryan)); // Jimmy > Eunice > Jose > Bryan
172+
System.out.println(shortestPath(Eugene, Jimmy, Kelvin)); // Jimmy > Eunice > Jose > Eugene > Kelvin
173+
System.out.println(shortestPath(Eugene, Eunice, Jimmy)); // Eunice > Jimmy
174+
System.out.println(shortestPath(Jose, Gabriel, Kelvin)); // null - out of CEO tree
175+
System.out.println(shortestPath(Jose, Gabriel, Dennis)); // Gabriel > Eunice > Jose > Dennis
176+
System.out.println(shortestPath(Eugene, Gabriel, Gabriel)); // Gabriel
177+
System.out.println(shortestPath(Kelvin, Gabriel, Terence)); // null - not in the tree
178+
}
179+
};

‎pre_interview/flintex/submitted.txt

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package shortestPath;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.HashMap;
7+
import java.util.HashSet;
8+
import java.util.Queue;
9+
import java.util.LinkedList;
10+
import java.util.Set;
11+
12+
public class Company {
13+
14+
// IMPORTANT: DO NOT MODIFY THIS CLASS
15+
public static class Employee {
16+
17+
private final int id;
18+
private final String name;
19+
private List<Employee> reports;
20+
21+
public Employee(int id, String name) {
22+
this.id = id;
23+
this.name = name;
24+
this.reports = new ArrayList<Employee>();
25+
}
26+
27+
public int getId() {
28+
return id;
29+
}
30+
31+
public String getName() {
32+
return name;
33+
}
34+
35+
public List<Employee> getReports() {
36+
return reports;
37+
}
38+
39+
public void addReport(Employee employee) {
40+
reports.add(employee);
41+
}
42+
43+
}
44+
45+
/*
46+
* Read the attached PDF for more explanation about the problem
47+
* Note: Don't modify the signature of this function
48+
* @param ceo
49+
*
50+
* @param firstEmployee - starting node
51+
*
52+
* @param secondEmployee - destination node
53+
*
54+
* @return the shortest path from First Employee to the Second Employee. Separated by " > " and return null if not found.
55+
*/
56+
@SuppressWarnings("unused")
57+
public static String shortestPath(Employee ceo, Employee firstEmployee, Employee secondEmployee) { // The time complexity: O(v + e); space complexity is: O(v + e)
58+
/*
59+
* My thought process:
60+
* when i see the word "shortest path", the first thing that comes into my mind is Djikstra's algorithm, but this is just simply hierarchical structure without distance/priority. This can be viewed as an undirected graph problem that each employee is a node, and reporting relationship forms the edges. (connectivity)
61+
*
62+
* A few assumptions:
63+
* - the ceo, first and second employees always exists in the organisation (graph) - otherwise not found case would be needed
64+
* - its an undirected graph as it is a hierarchical layout we do not need to handle cyclical behaviour
65+
* - there is no self report such as Bryan manages Bryan - my handling is just returning it's path which is the employee name when the same guy is entered for both 1st and 2nd employee
66+
* - edge cases like: no relationship between two employees under the CEO, we can just simply return null
67+
*
68+
*/
69+
70+
Map<Employee, List<Employee>> graph = new HashMap<>(); // adjacency list
71+
72+
// space: O(v)
73+
Set<Employee> visited = new HashSet<>();
74+
75+
// space: O(v)
76+
Queue<Employee> queue = new LinkedList<>(); // LinkedList is more efficient for BFS as ArrayList's removal is O(n); LinkedList is O(1) - as we are not accessing any of the elements at specific index (ArrayList) which costs O(n), so it's better to use a LinkedList.
77+
78+
// space: O(v)
79+
Map<Employee, Employee> prev = new HashMap<>(); // for tracing back the shortest path when we find that 1st == 2nd
80+
81+
// building the graph (adjacency list to store relationships btw employees)
82+
// time: O(v + e) - v: vertices, e: edges; space: O(v + e)
83+
addToGraph(graph, ceo);
84+
System.out.println(graph);
85+
86+
queue.add(firstEmployee);
87+
88+
// BFS - to find SP btw 2 nodes
89+
// time: O(v + e)
90+
while (!queue.isEmpty()) {
91+
Employee current = queue.poll();
92+
visited.add(current); // visit the node
93+
94+
if (current.equals(secondEmployee)) {
95+
StringBuilder path = new StringBuilder(); // build and return the path from 1st to 2nd employee
96+
97+
while (current != null) {
98+
if (!path.isEmpty()) {
99+
path.insert(0, " > "); // prepend a " > " before appending the name ONLY when it is not empty.
100+
}
101+
path.insert(0, current.getName()); // prepend name before the path
102+
current = prev.get(current); // get the next guy
103+
}
104+
105+
return path.toString();
106+
}
107+
108+
// exit (continue) early if not found in the adjacency list (graph)
109+
if (!graph.containsKey(current)) {
110+
continue;
111+
}
112+
113+
// Find the connection(s)
114+
// 0 - Gabriel -> G => [E];
115+
// 1 - Eunice -> E => [J, G, J]; // Jimmy is one of them. - later the cond above should match and return
116+
// in short, prev is more of like the previous visited lookup map, if we can find the 1st == 2nd employees, we can simply look back up to form the path, like:
117+
// e.g. Gabriel to fnd Jimmy
118+
// - the final map: {Eugene=Jose, Dennis=Jose, Eunice=Gabriel, Jose=Eunice, Jimmy=Eunice, Bryan=Jose}
119+
// when we find Jimmy, we can look back up from Jimmy -> Eunice -> Gabriel
120+
for (Employee next : graph.get(current)) {
121+
if (!visited.contains(next)) {
122+
queue.add(next);
123+
prev.put(next, current);
124+
}
125+
}
126+
}
127+
128+
return null; // There is no path between firstEmployee and secondEmployee
129+
}
130+
131+
// Helper function to add relationships to the graph
132+
private static void addToGraph(Map<Employee, List<Employee>> graph, Employee employee) {
133+
if (!graph.containsKey(employee)) {
134+
graph.put(employee, new ArrayList<>());
135+
}
136+
137+
for (Employee report : employee.getReports()) {
138+
if (!graph.containsKey(report)) {
139+
graph.put(report, new ArrayList<>());
140+
}
141+
142+
graph.get(employee).add(report);
143+
graph.get(report).add(employee);
144+
addToGraph(graph, report);
145+
}
146+
}
147+
148+
public static void main(String[] args) {
149+
Employee Eugene = new Employee(1, "Eugene");
150+
Employee Jose = new Employee(2, "Jose");
151+
Employee Kelvin = new Employee(3, "Kelvin");
152+
Employee Terence = new Employee(4, "Terence");
153+
Employee Dennis = new Employee(5, "Dennis");
154+
Employee Eunice = new Employee(6, "Eunice");
155+
Employee Bryan = new Employee(7, "Bryan");
156+
Employee Gabriel = new Employee(8, "Gabriel");
157+
Employee Jimmy = new Employee(9, "Jimmy");
158+
159+
Eugene.addReport(Jose);
160+
Eugene.addReport(Kelvin);
161+
Eugene.addReport(Terence);
162+
163+
Jose.addReport(Dennis);
164+
Jose.addReport(Eunice);
165+
Jose.addReport(Bryan);
166+
167+
Eunice.addReport(Gabriel);
168+
Eunice.addReport(Jimmy);
169+
170+
// Test cases
171+
System.out.println(shortestPath(Eugene, Gabriel, Jimmy)); // Gabriel > Eunice > Jimmy
172+
System.out.println(shortestPath(Eugene, Jimmy, Bryan)); // Jimmy > Eunice > Jose > Bryan
173+
System.out.println(shortestPath(Eugene, Jimmy, Kelvin)); // Jimmy > Eunice > Jose > Eugene > Kelvin
174+
System.out.println(shortestPath(Eugene, Eunice, Jimmy)); // Eunice > Jimmy
175+
System.out.println(shortestPath(Jose, Gabriel, Kelvin)); // null - out of CEO tree
176+
System.out.println(shortestPath(Jose, Gabriel, Dennis)); // Gabriel > Eunice > Jose > Dennis
177+
System.out.println(shortestPath(Eugene, Gabriel, Gabriel)); // Gabriel
178+
System.out.println(shortestPath(Kelvin, Gabriel, Terence)); // null - not in the tree
179+
}
180+
};

0 commit comments

Comments
 (0)
Please sign in to comment.