1
1
package com .ctci .treesandgraphs ;
2
2
3
+ import java .util .ArrayList ;
4
+ import java .util .HashMap ;
5
+ import java .util .HashSet ;
6
+ import java .util .LinkedHashMap ;
7
+ import java .util .List ;
8
+ import java .util .Map ;
9
+ import java .util .Set ;
10
+ import java .util .stream .Stream ;
11
+
3
12
/**
4
13
* @author rampatra
5
14
* @since 2019-02-21
6
15
*/
7
16
public class BuildOrder {
8
17
9
- // todo
10
-
18
+ private class Project {
19
+ String name ;
20
+ Set <Project > dependencies = new HashSet <>();
21
+
22
+ Project (String name ) {
23
+ this .name = name ;
24
+ }
25
+
26
+ @ Override
27
+ public String toString () {
28
+ return name ;
29
+ }
30
+ }
31
+
32
+ private final Map <String , Project > projects = new HashMap <>();
33
+
34
+ private void addProjects (Stream <String > projectNames ) {
35
+ projectNames .forEach (name -> projects .put (name , new Project (name )));
36
+ }
37
+
38
+ /**
39
+ * Adds a directed edge from {@code projectName2} to {@code ProjectName1}. This means {@code projectName2} is
40
+ * dependent on {@code projectName1}, i.e, {@code projectName1} has to be built before {@code projectName2}.
41
+ *
42
+ * @param projectName1 name of project 1
43
+ * @param projectName2 name of project 2
44
+ */
45
+ private void addDependency (String projectName1 , String projectName2 ) {
46
+ Project p1 = projects .get (projectName1 );
47
+ Project p2 = projects .get (projectName2 );
48
+
49
+ if (p1 == null ) {
50
+ p1 = new Project (projectName1 );
51
+ projects .put (projectName1 , p1 );
52
+ }
53
+ if (p2 == null ) {
54
+ p2 = new Project (projectName2 );
55
+ projects .put (projectName2 , p2 );
56
+ }
57
+
58
+ p2 .dependencies .add (p1 );
59
+ }
60
+
61
+ /**
62
+ * Determines the order in which the projects need to be built.
63
+ * Time complexity: TODO
64
+ *
65
+ * @return a list of projects in the order they should be built, the first project should be built first and so on.
66
+ */
67
+ private List <Project > getBuildOrder () {
68
+ Map <String , Project > projectsBuilt = new LinkedHashMap <>(); // linked hashmap is needed to maintain the insertion order
69
+
70
+ while (projectsBuilt .size () != projects .size ()) {
71
+ // find the projects which are not dependent on any project
72
+ Set <Project > nextProjectsToBuild = getProjectsWithNoDependencies (projectsBuilt );
73
+
74
+ // if there are no further independent projects to build, then we can't proceed further
75
+ if (nextProjectsToBuild .size () == 0 ) {
76
+ throw new IllegalStateException ("Error: Projects can't be built." );
77
+ }
78
+ nextProjectsToBuild .forEach (p -> projectsBuilt .put (p .name , p ));
79
+
80
+ // once a project is built, remove the dependencies from all other projects dependent on this
81
+ removeDependency (nextProjectsToBuild );
82
+ }
83
+
84
+ return new ArrayList <>(projectsBuilt .values ());
85
+ }
86
+
87
+ private Set <Project > getProjectsWithNoDependencies (Map <String , Project > alreadyBuildProjects ) {
88
+ Set <Project > unBuiltProjectsWithZeroDependencies = new HashSet <>();
89
+
90
+ for (Map .Entry <String , Project > entry : projects .entrySet ()) {
91
+ if (entry .getValue ().dependencies .size () == 0 && alreadyBuildProjects .get (entry .getKey ()) == null ) {
92
+ unBuiltProjectsWithZeroDependencies .add (entry .getValue ());
93
+ }
94
+ }
95
+
96
+ return unBuiltProjectsWithZeroDependencies ;
97
+ }
98
+
99
+ private void removeDependency (Set <Project > newlyBuiltProjects ) {
100
+ projects .forEach ((n , p ) -> p .dependencies .removeAll (newlyBuiltProjects ));
101
+ }
102
+
103
+
11
104
public static void main (String [] args ) {
105
+ /* test case 1
12
106
107
+ ––––––––––– b
108
+ | ↑
109
+ ↓ |
110
+ f <–– a <–– d <–– c
111
+
112
+
113
+ */
114
+ BuildOrder buildOrder = new BuildOrder ();
115
+ buildOrder .addProjects (Stream .of ("a" , "b" , "c" , "d" , "e" , "f" ));
116
+ buildOrder .addDependency ("a" , "d" );
117
+ buildOrder .addDependency ("f" , "b" );
118
+ buildOrder .addDependency ("b" , "d" );
119
+ buildOrder .addDependency ("f" , "a" );
120
+ buildOrder .addDependency ("d" , "c" );
121
+ System .out .println (buildOrder .getBuildOrder ());
122
+
123
+ // test case 2
124
+ buildOrder = new BuildOrder ();
125
+ buildOrder .addProjects (Stream .of ("a" , "b" , "c" , "d" , "e" , "f" , "g" ));
126
+ buildOrder .addDependency ("d" , "g" );
127
+ buildOrder .addDependency ("f" , "b" );
128
+ buildOrder .addDependency ("f" , "c" );
129
+ buildOrder .addDependency ("f" , "a" );
130
+ buildOrder .addDependency ("c" , "a" );
131
+ buildOrder .addDependency ("b" , "a" );
132
+ buildOrder .addDependency ("b" , "e" );
133
+ buildOrder .addDependency ("a" , "e" );
134
+ System .out .println (buildOrder .getBuildOrder ());
13
135
}
14
- }
136
+ }
0 commit comments