diff --git a/src/Practice.java b/src/Practice.java index 1dcdfb1..efd26fe 100644 --- a/src/Practice.java +++ b/src/Practice.java @@ -1,72 +1,161 @@ +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Stack; public class Practice { /** - * Returns the count of vertices with odd values that can be reached from the given starting vertex. + * Returns the count of vertices with odd values that can be reached from the + * given starting vertex. * The starting vertex is included in the count if its value is odd. * If the starting vertex is null, returns 0. * * Example: * Consider a graph where: - * 5 --> 4 - * | | - * v v - * 8 --> 7 < -- 1 - * | - * v - * 9 + * 5 --> 4 + * | | + * v v + * 8 --> 7 < -- 1 + * | + * v + * 9 * * Starting from 5, the odd nodes that can be reached are 5, 7, and 9. * Thus, given 5, the number of reachable odd nodes is 3. + * * @param starting the starting vertex (may be null) - * @return the number of vertices with odd values reachable from the starting vertex + * @return the number of vertices with odd values reachable from the starting + * vertex */ public static int oddVertices(Vertex starting) { - return 0; + if (starting == null) { + return 0; + } + + Set> visited = new HashSet<>(); + return oddVerticesHelper(starting, visited); + + } + + public static int oddVerticesHelper(Vertex starting, Set> visited) { + + if (starting == null || visited.contains(starting)) { + return 0; + } + + visited.add(starting); + + int counter = (starting.data % 2 != 0) ? 1 : 0; + + for (var vertex : starting.neighbors) { + + counter += oddVerticesHelper(vertex, visited); + } + + return counter; } /** - * Returns a *sorted* list of all values reachable from the starting vertex (including the starting vertex itself). + * Returns a *sorted* list of all values reachable from the starting vertex + * (including the starting vertex itself). * If duplicate vertex data exists, duplicates should appear in the output. * If the starting vertex is null, returns an empty list. * They should be sorted in ascending numerical order. * * Example: * Consider a graph where: - * 5 --> 8 - * | | - * v v - * 8 --> 2 <-- 4 + * 5 --> 8 + * | | + * v v + * 8 --> 2 <-- 4 * When starting from the vertex with value 5, the output should be: - * [2, 5, 8, 8] + * [2, 5, 8, 8] * * @param starting the starting vertex (may be null) - * @return a sorted list of all reachable vertex values by + * @return a sorted list of all reachable vertex values by */ public static List sortedReachable(Vertex starting) { - // Unimplemented: perform a depth-first search and sort the collected values. - return null; + if (starting == null) { + return new ArrayList<>(); + } + + Set> visited = new HashSet<>(); + return sortedReachableHelper(starting, visited); + + } + + public static List sortedReachableHelper(Vertex starting, Set> visited) { + if (starting == null || visited.contains(starting)) + return new ArrayList<>(); + ; + + visited.add(starting); + + for (var vertex : starting.neighbors) { + sortedReachableHelper(vertex, visited); + } + + // adding + + List sortedList = new ArrayList<>(); + + for (var vertex : visited) { + sortedList.add(vertex.data); + } + + Collections.sort(sortedList); + + return sortedList; + } /** - * Returns a sorted list of all values reachable from the given starting vertex in the provided graph. - * The graph is represented as a map where each key is a vertex and its corresponding value is a set of neighbors. + * Returns a sorted list of all values reachable from the given starting vertex + * in the provided graph. + * The graph is represented as a map where each key is a vertex and its + * corresponding value is a set of neighbors. * It is assumed that there are no duplicate vertices. - * If the starting vertex is not present as a key in the map, returns an empty list. + * If the starting vertex is not present as a key in the map, returns an empty + * list. * - * @param graph a map representing the graph + * @param graph a map representing the graph * @param starting the starting vertex value * @return a sorted list of all reachable vertex values */ public static List sortedReachable(Map> graph, int starting) { - return null; + if (graph == null || !graph.containsKey(starting)) + return new ArrayList<>(); + + Set visited = new HashSet<>(); + return sortedReachableHelper(graph, starting, visited); + + } + + public static List sortedReachableHelper(Map> graph, int starting, + Set visited) { + if (visited.contains(starting)) + return new ArrayList<>(); + + visited.add(starting); + List sortedList = new ArrayList<>(); + sortedList.add(starting); + + for (var neighbor : graph.get(starting)) { + sortedList.addAll(sortedReachableHelper(graph, neighbor, visited)); + } + + Collections.sort(sortedList); + return sortedList; } /** - * Returns true if and only if it is possible both to reach v2 from v1 and to reach v1 from v2. + * Returns true if and only if it is possible both to reach v2 from v1 and to + * reach v1 from v2. * A vertex is always considered reachable from itself. * If either v1 or v2 is null or if one cannot reach the other, returns false. * @@ -75,40 +164,142 @@ public static List sortedReachable(Map> graph, in * If v1 equals v2, the method should also return true. * * @param the type of data stored in the vertex - * @param v1 the starting vertex - * @param v2 the target vertex - * @return true if there is a two-way connection between v1 and v2, false otherwise + * @param v1 the starting vertex + * @param v2 the target vertex + * @return true if there is a two-way connection between v1 and v2, false + * otherwise */ public static boolean twoWay(Vertex v1, Vertex v2) { + if (v1 == null || v2 == null) + return false; + + if (v1 == v2) + return true; + + return twoWayHelper(v1, v2) && twoWayHelper(v2, v1); + + } + + private static boolean twoWayHelper(Vertex start, Vertex target) { + + Set> visited = new HashSet<>(); + Stack> stack = new Stack<>(); + + stack.push(start); + + while (!stack.isEmpty()) { + Vertex current = stack.pop(); + if (current.equals(target)) + return true; + + if (visited.contains(current)) { + continue; + } else { + visited.add(current); + } + + for (Vertex neighbor : current.neighbors) { + stack.push(neighbor); + } + } + return false; + } /** - * Returns whether there exists a path from the starting to ending vertex that includes only positive values. + * Returns whether there exists a path from the starting to ending vertex that + * includes only positive values. * - * The graph is represented as a map where each key is a vertex and each value is a set of directly reachable neighbor vertices. A vertex is always considered reachable from itself. - * If the starting or ending vertex is not positive or is not present in the keys of the map, or if no valid path exists, + * The graph is represented as a map where each key is a vertex and each value + * is a set of directly reachable neighbor vertices. A vertex is always + * considered reachable from itself. + * If the starting or ending vertex is not positive or is not present in the + * keys of the map, or if no valid path exists, * returns false. * - * @param graph a map representing the graph + * @param graph a map representing the graph * @param starting the starting vertex value - * @param ending the ending vertex value + * @param ending the ending vertex value * @return whether there exists a valid positive path from starting to ending */ public static boolean positivePathExists(Map> graph, int starting, int ending) { + + if (starting <= 0) { + return false; + } + if (starting == ending) + return true; + + Set visited = new HashSet<>(); + Stack stack = new Stack<>(); + + stack.push(starting); + + while (!stack.isEmpty()) { + int current = stack.pop(); + + if (visited.contains(current)) + // this tells it to skip everything essentially? + // tales the next item from the stack! + continue; + visited.add(current); + + if (current == ending) + return true; + + if (graph.containsKey(current)) { + for (var neighbor : graph.get(current)) { + if (!visited.contains(neighbor) && neighbor > 0) { + stack.push(neighbor); + } + } + } + + } return false; } /** - * Returns true if a professional has anyone in their extended network (reachable through any number of links) - * that works for the given company. The search includes the professional themself. + * Returns true if a professional has anyone in their extended network + * (reachable through any number of links) + * that works for the given company. The search includes the professional + * themself. * If the professional is null, returns false. * - * @param person the professional to start the search from (may be null) + * @param person the professional to start the search from (may be null) * @param companyName the name of the company to check for employment - * @return true if a person in the extended network works at the specified company, false otherwise + * @return true if a person in the extended network works at the specified + * company, false otherwise */ public static boolean hasExtendedConnectionAtCompany(Professional person, String companyName) { + + Set visited = new HashSet<>(); + + return hasExtendedConnectionAtCompanyHelper(person, companyName, visited); + + } + + public static boolean hasExtendedConnectionAtCompanyHelper(Professional person, String companyName, + Set visited) { + if (person == null || companyName == null) + return false; + + if (person.getCompany().equals(companyName)) + return true; + + if (visited.contains(person)) { + return false; + } + + visited.add(person); + + for (var people : person.getConnections()) { + if (hasExtendedConnectionAtCompanyHelper(people, companyName, visited)) { + return true; + } + } + return false; } }