javaalgorithmgraph-algorithmunion-find

Java algorithm problem: output one of the two connected paths


/**
* The Problem:
*
* We have a list of tasks. Each task can depend on other tasks. 
* For example if task A depends on task B then B should run before A.
* 
* Implement the "getTaskWithDependencies" method such that it returns a list of task names in the correct order.
* 
* For example if I want to execute task "application A", the method should return a list with "storage,mongo,application A".
*
* List of Tasks:
*
*   - name: application A
*     dependsOn:
*       - mongo
*
*   - name: storage
*
*   - name: mongo
*     dependsOn:
*       - storage
*
*   - name: memcache
*
*   - name: application B
*     dependsOn:
*       - memcache
*
* The Java program is expected to be executed succesfully.
*/
public class Solution { 
 private static List<String> getTaskWithDependencies(List<Task> tasks, String dependsOn) {
   // TODO: please implement logic here
   
 }
  
  

 @Test
 public void testGetTaskDependenciesForApplicationA() {
   Assert.assertEquals(
     Arrays.asList(
       "storage",
       "mongo",
       "application A"
     ),
     getTaskWithDependencies(TaskList.getTasks(), "application A")
   );
 }
}

/**
* Definition of a Task
*/
class Task {
 private final String name;
 private final List<String> dependsOn;

 Task(String name) {
   this(name, new ArrayList<>());
 }

 Task(String name, List<String> dependsOn) {
   this.name = name;
   this.dependsOn = dependsOn;
 }

 public String getName() { return this.name; }
 public List<String> getDependsOn() { return this.dependsOn; }
}

class TaskList {
 public static List<Task> getTasks() {
   List<Task> tasks = new ArrayList<>();

   tasks.add(new Task("application A", Arrays.asList("mongo")));
   tasks.add(new Task("storage"));
   tasks.add(new Task("mongo", Arrays.asList("storage")));
   tasks.add(new Task("memcache"));
   tasks.add(new Task("application B", Arrays.asList("memcache")));

   return tasks;
 }
}

The general idea is to give some directional relationships, including: application a -> mongodb -> storage This is a connecting path application b -> memcache This is a connecting path, Now that application A is specified, it is required to output the connected path where it is. My approach is to sort these 5 points together using topological sorting. The result will be b->memcache->a->mongo->storage. My question is: how to output only one connected path and ignore the other? I read there is no similar question in Leetcode, so there is no idea. I can write the code by myself, and it’s good to be able to tell me the idea.


Solution

  • You can use recursion to solve your problem.

    From the list of tasks passed in the method, fetch the one with dependsOn through filtering by name of the task. If the task has it's own dependsOn list, iterate through the list and call the recursive function passing the same list of tasks and the iterated string as newDependsOn to it. Append all the results you get from the recursive function in a comma separated StringBuilder with a "," which will be used as delimiter for producing final list.

    After all these completion of iteration, append the initial dependsOn to the StringBuilder. Finally, return the StrinBuilder.toStirng().split(",") as list to get the final result.

    NOTE: I've written the code but as per as your request I haven't added it to this answer. If you need further help, ask me in the comment, I'll provide the code if needed.

    Update

    As per your request I'm adding the code below:

    private static List<String> getTaskWithDependencies(List<Task> tasks, String dependsOn) {
        StringBuilder resultString = new StringBuilder();
        Task task = tasks.stream().filter(x -> dependsOn.equalsIgnoreCase(x.getName())).findAny().get();
        if (task.getDependsOn() != null && !task.getDependsOn().isEmpty()) {
            for (String newDependsOn : task.getDependsOn()) {
                List<String> res = getTaskWithDependencies(tasks, newDependsOn);
                for (String ele : res) {
                    resultString.append(ele).append(",");
                }
            }
        }
        resultString.append(dependsOn);
        return Arrays.asList(resultString.toString().split(","));
    }
    

    Now if you run the code with this:

    public static void main(String[] args) {
        System.out.println(getTaskWithDependencies(TaskList.getTasks(), "application A"));
    }
    

    You'll get the following output:

    [storage, mongo, application A]