Follow list path with recursion. [Java] - java

Hello i have a list with different connections. I want a function that allows me to give a start and end value. The function needs to figure out if there is a path. And if there's a path, it needs to be returned. I already created a working program. But the only thing is that i only get if there is a path yes or no. But i want to get the path.
private static String[] connections = {
"Strawberry -> Apple",
"Apple -> Strawberry",
"Strawberry -> Melon",
"Melon -> Strawberry"
};
public static void main(String[] args) {
System.out.println(testConnection("Apple", "Melon", new ArrayList<>()));
}
public static boolean testConnection(String from, String to, List<String> checked) {
if(from.equals(to)) return true;
for(String con : connections) {
String[] conSplit = con.split(" -> ");
String first = conSplit[0];
String second = conSplit[1];
if(first.equals(from)) {
if(second.equals(to)) return true;
if(checked.contains(second)) continue;
checked.add(first);
if(testConnection(second, to, checked)) return true;
}
}
return false;
}
As you see Apple goes to Strawberry, Strawberry goes to Melon.
And in my testConnection I said that i need to get the path from Apple to Melon.

You can use many ways to do that.
In these cases I don't like to use recursion, but it's up to you.
For example you can just use the print statement in your loop to print first and second strings when the statement if(first.equals(from)) returns true.
Here is my version of the testConnection method using iteration:
public static boolean testConnection(String from, String to, List<String> checked) {
boolean flag = false;
for (String con : connections) {
String[] conSplit = con.split(" -> ");
String first = conSplit[0];
String second = conSplit[1];
if (first.equals(from)) {
checked.add(first);
checked.add(second);
from = second;
if (second.equals(to)) {
flag = true;
break;
}
}
}
if (flag)
System.out.println(checked);
return flag;
}

Looking at the checked list is not sufficient to construct the path, since it will only be the same as the path if no backtracking is used. For example, with the connections:
private static String[] connections = {
"Strawberry -> Apple",
"Apple -> Pineapple",
"Apple -> Strawberry",
"Strawberry -> Cherry",
"Cherry -> Apple",
"Strawberry -> Melon",
"Melon -> Strawberry",
};
You would end up checking Apple, Pineapple, Strawberry, Cherry then Melon, even though the path is Apple, Strawberry, Melon. A separate list is needed to find the path, e.g.:
public static boolean testConnection(String from, String to, List<String> checked, Stack<String> path) {
checked.add(from);
path.add(from);
if (from.equals(to)) return true;
for (String con : connections) {
String[] conSplit = con.split(" -> ");
String first = conSplit[0];
String second = conSplit[1];
if (first.equals(from)) {
if (second.equals(to)) {
path.add(second);
return true;
}
if (checked.contains(second)) continue;
if (testConnection(second, to, checked, path)) return true;
}
}
path.pop();
return false;
}
The key is that if all the connections are checked and no path is found, then the item is removed from the end of the path (path.pop()). This means that if a path is explored and then it is found that it doesn't lead to the destination, it won't affect the final path.
This algorithm is quite inefficient however, since every iteration it loops over every single connection. This can be fixed by building a graph data structure:
class Node {
String name;
List<Node> nextNodes;
public Node(String name) {
this.name = name;
this.nextNodes = new ArrayList<>();
}
public static Map<String, Node> fromConnections(String[] connections) {
Map<String, Node> nodes = new HashMap<>();
for (String con :
connections) {
String[] conSplit = con.split(" -> ");
String first = conSplit[0];
String second = conSplit[1];
Node node = nodes.computeIfAbsent(first, Node::new);
node.nextNodes.add(nodes.computeIfAbsent(second, Node::new));
}
return nodes;
}
}
This only loops over the entire list once. Now finding the connections that lead from a node only involves looping over those connections, not the entire list. It also separates the parsing stage from the search stage. Lastly, when you are going to do many checked.contains(second) checks, it is more efficient to use a HashSet rather than a list. Checking if a list contains an element involves looping over the entire list, whereas checking if a hashset contains something takes the same amount of time regardless of the size of the hashset.
Here is a running example of both versions of the algorithm:
import java.util.*;
public class Main {
static class Node {
String name;
List<Node> nextNodes;
public Node(String name) {
this.name = name;
this.nextNodes = new ArrayList<>();
}
public static Map<String, Node> fromConnections(String[] connections) {
Map<String, Node> nodes = new HashMap<>();
for (String con :
connections) {
String[] conSplit = con.split(" -> ");
String first = conSplit[0];
String second = conSplit[1];
Node node = nodes.computeIfAbsent(first, Node::new);
node.nextNodes.add(nodes.computeIfAbsent(second, Node::new));
}
return nodes;
}
}
private static String[] connections = {
"Strawberry -> Apple",
"Apple -> Pineapple",
"Apple -> Strawberry",
"Strawberry -> Cherry",
"Cherry -> Apple",
"Strawberry -> Melon",
"Melon -> Strawberry",
};
public static void main(String[] args) {
Stack<String> path = new Stack<>();
ArrayList<String> checked = new ArrayList<>();
System.out.println(testConnection("Apple", "Melon", checked, path));
System.out.println(path);
System.out.printf("checked: %s\n", checked);
Map<String, Node> graph = Node.fromConnections(connections);
path = new Stack<>();
System.out.println(testConnection(graph.get("Apple"), graph.get("Melon"), new HashSet<>(), path));
System.out.println(path);
}
public static boolean testConnection(String from, String to, List<String> checked, Stack<String> path) {
checked.add(from);
path.add(from);
if (from.equals(to)) return true;
for (String con : connections) {
String[] conSplit = con.split(" -> ");
String first = conSplit[0];
String second = conSplit[1];
if (first.equals(from)) {
if (second.equals(to)) {
path.add(second);
return true;
}
if (checked.contains(second)) continue;
if (testConnection(second, to, checked, path)) return true;
}
}
path.pop();
return false;
}
public static boolean testConnection(Node from, Node to, Set<Node> checked, Stack<String> path) {
checked.add(from);
path.add(from.name);
if (from == to) return true;
for (Node next : from.nextNodes) {
if (checked.contains(next)) continue;
if (testConnection(next, to, checked, path)) return true;
}
path.pop();
return false;
}
}

Related

Find a particular word in a string array of sentences and return the frequency of a particular word throughout the array

The input is String array as below,
{"1112323 400 error","1112323 400 error","9988778 400 error"}
I need to print the timestamp i.e the number at the start of the sentences and its frequency throughout the array
I've come only this far as of now. Only have been able to find the string if it is known already.
int count = 0;
for(int i=str1.length-1;i>=0;i--)
{
String[] ElementOfArray = str1[i].split(" ");
for(int j=0;j<ElementOfArray.length-1;j++)
{
if(ElementOfArray[j].equals("Hi"))
{
count++;
}
}
}
System.out.println(count);
One approach is to keep track of the number of entries, and increment.
public static void main(String[] args)
{
String[] inp = {"1112323 400 error",
"1112323 400 error",
"9988778 400 error"};
Map<String,Integer> results = new HashMap<>();
for (String one : inp) {
String[] parts = one.split(" ");
String ts = parts[0];
int val = results.computeIfAbsent(ts, v-> 0);
results.put(ts, ++val);
}
System.out.println(results);
}
Note: there are other ways to handle the map incrementing. This is just one example.
Sample Output:
{1112323=2, 9988778=1}
Now, if in the future one might want to perform other operations, using objects might be of interest.
So a class might be:
private static class Entry
{
private final String ts;
private final String code;
private final String desc;
public Entry(String ts, String code, String desc)
{
// NOTE: error handling is needed
this.ts = ts;
this.code = code;
this.desc = desc;
}
public String getTs()
{
return ts;
}
public static Entry fromLine(String line)
{
Objects.requireNonNull(line, "Null line input");
// NOTE: other checks would be good
String[] parts = line.split(" ");
// NOTE: should verify the basic parts
return new Entry(parts[0], parts[1], parts[2]);
}
// other getter methods
}
And then one could do something like:
List<Entry> entries = new ArrayList<>();
for (String one : inp) {
entries.add(Entry.fromLine(one));
}
Map<String,Integer> res2 = entries.stream()
.collect(Collectors.groupingBy(x->x.getTs(),
Collectors.summingInt(x -> 1)));
System.out.println(res2);
(same sample output at the moment). But if one needs to extend to count the number of 400 codes or whatever, it is trivial to change the stream since the object has the data. Of course, there are even more extensions to this approach.
You can use HashMap to solve count the frequency of timestamps.
import java.util.HashMap;
public class test {
public static void main(String[] args) {
// Create a HashMap object called timeFrequency
HashMap<String, Integer> timeFrequency = new HashMap<String, Integer>();
String []str1 = {"1112323 400 error","1112323 400 error","9988778 400 error"};
for(int i=0;i<str1.length;i++)
{
String[] ElementOfArray = str1[i].split(" ");
if(timeFrequency.containsKey(ElementOfArray[0])){
timeFrequency.put(ElementOfArray[0], timeFrequency.get(ElementOfArray[0]) + 1);
}else{
timeFrequency.put(ElementOfArray[0], 1);
}
}
System.out.println(timeFrequency);
}
}
Output:
{1112323=2, 9988778=1}

2-D array Friends of Friends List

2*2 Matrix
Men Friends
A B,C,D
B E,F
C A
E B
F B
G F
I need list of Friends and Friends of Friends for requested men.
Example Like G -> F,B,E,F,B and After removing duplicate F,B,E
I resolved it with loops and recursion but not satisfied
Need better approach/suggestion.. rest i will implement.
Why not try something like this. Of course, i have taken a bit of freedom on the design as you didnt provide any code. Hope this helps!
private static Set<Node> getNodesFollowAllEdges(Node node) {
Set<Node> nodes = getNodesFollowAllEdges(node, new HashSet<>());
// remember to remove the original node from the set
nodes.remove(node);
return nodes;
}
private static Set<Node> getNodesFollowAllEdges(Node node, Set<Node> visited) {
if (node.getConnectedNodes().isEmpty()) {
return visited;
}
for (Node n : node.getConnectedNodes()) {
if (!visited.contains(n)) {
visited.add(n);
getNodesFollowAllEdges(n, visited);
}
}
return visited;
}
Also, it is very easy to provide a maximum search dept. Just add int maxDept and increase it every recursion step.
Given the following example:
Node a = new Node("A");
Node b = new Node("B");
Node c = new Node("C");
Node d = new Node("D");
Node e = new Node("E");
Node f = new Node("F");
Node g = new Node("G");
a.addConnectedNodes(b, c, d);
b.addConnectedNodes(e, f);
c.addConnectedNodes(a);
e.addConnectedNodes(b);
f.addConnectedNodes(b);
g.addConnectedNodes(f);
Set<Node> friends = getNodesFollowAllEdges(a);
friends.forEach(node -> System.out.println(node.getName()));
should give you the correct result of (order neglected)
B
F
E
Note: Remember that, since its a Set, the resulting nodes can be in any order.
Thanks Glains,
My Code is :
public class Demo {
Set<String> freinds = new HashSet<>();
public static void main(String[] args) {
String[][] emailArray = new String[][] {
{ "abc#gmail.com", "abc1#gmail.com,abc2#gmail.com,abc3#gmail.com,1212#gmail.com" },
{ "abc1#gmail.com", "bcs1#gmail.combc2#gmail.com,bcds3#gmail.com" },
{ "bc#gmail.com", "bc1#gmail.combc2#gmail.com,bc3#gmail.com" } };
new Demo().sendMail("#gmail.combc2#gmail.com", "sdsd", emailArray);
}
void sendMail(String email, String message, String[][] freindsArray) {
Map<String, Email> emailsMap = new HashMap<>();
for (int i = 0; i < freindsArray.length; i++) {
for (int j = 0; j < 1; j++) {
Email e = new Email(freindsArray[i][j]);
e.addConnectedNodes(freindsArray[i][j + 1]);
emailsMap.put(e.email, e);
}
}
if (emailsMap.containsKey(email)) {
Demo.getNodesFollowAllEdges(emailsMap.get(email), emailsMap).forEach(e -> {
System.out.println(e);
});
} else {
System.out.println("no emails exist");
}
}
private static Set<String> getNodesFollowAllEdges(Email e, Map<String, Email> emailsMap) {
Set<String> nodes = getNodesFollowAllEdges(e, new HashSet<>(), emailsMap);
nodes.remove(e.email);
return nodes;
}
private static Set<String> getNodesFollowAllEdges(Email node, Set<String> visited, Map<String, Email> emailsMap) {
if (node.getConnectedEmails().isEmpty()) {
return visited;
}
for (String n : node.getConnectedEmails()) {
if (!visited.contains(n)) {
visited.add(n);
if (emailsMap.get(n) != null) {
getNodesFollowAllEdges(emailsMap.get(n), visited, emailsMap);
}
}
}
return visited;
}
}
class Email {
String email;
List<String> freindsEmails = new ArrayList<>();
public List<String> getConnectedEmails() {
return freindsEmails;
}
public Email(String email) {
this.email = email;
}
public void addConnectedNodes(String friendsEmail) {
freindsEmails.addAll(Arrays.asList(friendsEmail.split(",")));
}
}

Sorting using comparable

Intro
My code to do a custom sort by using Comparable is not work the way I want it to. I'm basically taking an Array of directories and sorting them by:
First number of directories, the fewer comes first.
If it's a tie alphabetically.
The problem
An example of an input you be:
["/", "/usr/", "/usr/local/", "/usr/local/bin/", "/games/",
"/games/snake/", "/homework/", "/temp/downloads/" ]
Which should return this:
["/", "/games/", "/homework/", "/usr/", "/games/snake/",
"/temp/downloads/", "/usr/local/", "/usr/local/bin/" ]
But for some reason my code is return this:
["/", "/usr/", "/games/", "/homework/", "/usr/local/",
"/games/snake/", "/usr/local/bin/", "/temp/downloads/" ]
My code [edited with comments]
import java.util.*;
public class Dirsort { public String[] sort(String[] dirs) {
//Creates Array list containing Sort object
ArrayList<Sort> mySort = new ArrayList<Sort>();
//Loop that gets the 3 needed values for sorting
for (String d: dirs){
String [] l = d.split("/");//String array for alphabetical comparison
int di = d.length();//Length of array for sorting by number of directories
mySort.add(new Sort(di,l,d));//adds Sort object to arraylist (note d (the entire directory) is needed for the toString)
}
Collections.sort(mySort);//sorts according to compareTo
String [] ans = new String [mySort.size()];//Creates a new string array that will be returned
int count = 0;//to keep track of where we are in the loop for appending
for (Sort s: mySort){
ans[count] = s.toString();
count++;
}
return ans;
}
class Sort implements Comparable<Sort>{
private int d;//number of directories
private String [] arr;//array of strings of names of directories
private String dir;//full directory as string for toString
//Constructor
public Sort(int myD, String [] myArr, String myDir){
d = myD;
arr = myArr;
dir = myDir;
}
//toString
public String toString(){
return dir;
}
#Override
public int compareTo(Sort arg0) {
// TODO Auto-generated method stub
//If they are the same return 0
if (this.equals(arg0)){
return 0;
}
//if the directories are empty
if("/".equals(arg0.dir)){
return 1;
}
if ("/".equals(this.dir)){
return -1;
}
//If they are not the same length the shorter one comes first
if (this.d != arg0.d){
return this.d - arg0.d;
}
//If they are the same length, compare them alphabetically
else{
for (int i = 0; i < arg0.d; i++){
if (!this.arr[i].equals(arg0.arr[i])){
return this.arr[i].compareTo(arg0.arr[i]);
}
}
}
return 0;
}
}
}
The bug is here:
for (String d: dirs){
String [] l = d.split("/");
int di = d.length(); // <- here
mySort.add(new Sort(di,l,d));
}
Because there you are comparing the length of the entire directory String, not the number of 'folders' in the directory. That's why "/usr/" comes before "/homework/", for example, because:
"/usr/".length() == 5
"/homework/".length() == 10
I believe what you wanted was this, using the length of the split:
int di = l.length;
Then the output is:
/
/games/
/homework/
/usr/
/games/snake/
/temp/downloads/
/usr/local/
/usr/local/bin/
There's another small bug though (possibly), which is that calling split on a String that starts with the delimiter will result in an empty String at the beginning.
IE:
"/usr/".split("/") == { "", "usr" }
So you might want to do something about that. Though here it means that all of them start with the empty String so it doesn't end up with an effect on the way you're doing the comparison.
And as a side note, it's also true what #JBNizet is suggesting that giving your variables more meaningful names helps a lot here. fullDir.length() and splitDir.length would have made this much easier to spot (and it may have never happened in the first place).
Here's a fixed version of your code, which handles the case where both directories are "/", which removes the unnecessary, and incorrectly passed length of the parts array, and which uses more meaningful variable names:
public class Dirsort {
public static void main(String[] args) {
String[] input = new String[] {
"/",
"/usr/",
"/usr/local/",
"/usr/local/bin/",
"/games/",
"/games/snake/",
"/homework/",
"/temp/downloads/"
};
String[] result = new Dirsort().sort(input);
System.out.println("result = " + Arrays.toString(result));
}
public String[] sort(String[] dirs) {
ArrayList<Sort> sorts = new ArrayList<Sort>();
for (String dir : dirs) {
String[] parts = dir.split("/");
sorts.add(new Sort(parts, dir));
}
Collections.sort(sorts);
String[] result = new String[sorts.size()];
int count = 0;
for (Sort sort: sorts) {
result[count] = sort.toString();
count++;
}
return result;
}
class Sort implements Comparable<Sort> {
private String[] parts;
private String dir;
public Sort(String[] parts, String dir) {
this.parts = parts;
this.dir = dir;
}
public String toString(){
return dir;
}
#Override
public int compareTo(Sort other) {
if (this.equals(other)){
return 0;
}
if("/".equals(other.dir) && "/".equals(dir)) {
return 0;
}
if("/".equals(other.dir)){
return 1;
}
if ("/".equals(this.dir)){
return -1;
}
if (this.parts.length != other.parts.length){
return this.parts.length - other.parts.length;
}
else {
for (int i = 0; i < other.parts.length; i++){
if (!this.parts[i].equals(other.parts[i])){
return this.parts[i].compareTo(other.parts[i]);
}
}
}
return 0;
}
}
}
I spotted the problem by simply using my debugger and make it display the value of all the variables.
public class Disort
{
public static String[] sort(String[] dirs)
{
ArrayList<Path> mySort = new ArrayList<Path>();
Path pathDir;
for(String dir : dirs){
pathDir = Paths.get(dir);
// check if directory exists
if(Files.isDirectory(pathDir)){
mySort.add(pathDir);
}
}
// sort the ArrayList according a personalized comparator
Collections.sort(mySort, new Comparator<Path>(){
#Override
public int compare(Path o1, Path o2)
{
if(o1.getNameCount() < o2.getNameCount()){
return -1;
}
else if(o1.getNameCount() > o2.getNameCount()){
return 1;
}
else{
return o1.compareTo(o2);
}
}
});
// to return a String[] but it will better to return a ArrayList<Path>
String[] result = new String[mySort.size()];
for(int i = 0; i < result.length; i++){
result[i] = mySort.get(i).toString();
}
return result;
}
}

Calling a method (hashmap/ hashset) from one class on a string in another.

My code is:
public class Main{
public static void main(String[] args){
WordGroup wordgroupOne= new WordGroup ("You can discover more about a person in an hour of play than in a year of conversation");
WordGroup wordgroupTwo= new WordGroup ( "When you play play hard when you work dont play at all");
String[] quoteOne = wordgroupOne.getWordArray();
String[] quoteTwo = wordgroupTwo.getWordArray();
for (String words : quoteOne){
System.out.println(words);
}
for (String words : quoteTwo){
System.out.println(words);
}
}
}
WordGroup class:
import java.util.HashSet;
import java.util.HashMap;
public class WordGroup {
public String words;
public WordGroup (String getWords){
words = getWords.toLowerCase();
}
public String[] getWordArray(){
return words.split(" ");
}
public HashSet<String> getWordSet(){
HashSet<String> set = new HashSet<String>();
String[] p = getWordArray();
for (String items : p){
set.add(items);
}
System.out.println(set);
return set;
}
public HashMap<String, Integer> getWordCounts() {
HashMap<String, Integer> map = new HashMap<String, Integer>();
String[] q = getWordArray();
for (String stuff : q) {
Integer oldVal = map.get(stuff);
if (oldVal == null){
oldVal = 0;
}
map.put(stuff, oldVal+1);
}
System.out.println(map);
return map;
}
}
What I am trying to do is use the getWordSet() method using the two WordGroups and
iterate or loop over the HashSet returned and print the words from it.
Call getWordCounts() on the two WordGroups. Use keySet() to retrieve the set of keys. Loop over this set and print out the word and its count for both WordGroups.
Use the getWordSet() method to make complete set of all the words from both WordGroups.
Loop over the new HashSet to print a complete list of all words with the sum counts from each of the hashmaps.
I am struggling with all of these. Any help is much appreciated!!
If you want to create a combined list or set, you will have to merge the lists together and the maps together. I leave that exercise to you.
public static void main(String[] args)
{
WordGroup wg1 = new WordGroup(
"You can discover more about a person in an hour of play than in a year of conversation");
WordGroup wg2 = new WordGroup(
"When you play play hard when you work dont play at all");
wg1.processWord();
// iterate through all the distinct words
Set<String> dw1 = wg1.getDistinctWords();
for (String s : dw1)
{
System.out.println(s);
}
// use map entry to iterate through the entry set
Map<String, Integer> wc1 = wg1.getWordCounts();
for (Map.Entry<String, Integer> entry : wc1.entrySet())
{
if (entry != null)
{
// use stringbuilder to build a temp string
// instead of using +
StringBuilder sb = new StringBuilder();
sb.append(entry.getKey());
sb.append(": ");
sb.append(entry.getValue());
System.out.println(sb);
}
}
}
public class WordGroup
{
// as a class, made the results of the process private
private String originalWord;
// we declare generic versions of the Collections, instead of the specific
// implementation
private Set<String> distinctWords;
private Map<String, Integer> wordCounts;
public WordGroup(String s)
{
this.originalWord = s;
// here we declare and initialize the specific implementation
this.distinctWords = new HashSet<String>();
this.wordCounts = new HashMap<String, Integer>();
}
public void processWord()
{
List<String> toProcess = getWordList();
if (toProcess != null && !toProcess.isEmpty())
{
for (String s : toProcess)
{
// the set will automatically figure out if it should be in the
// set or not.
this.distinctWords.add(s);
// call the update or insert method
upsertString(s);
}
}
}
// this splits the string into a list
// you could probably use a utility class from guava or something to do this
// but i have coded a naive version
private List<String> getWordList()
{
List<String> splitList = new ArrayList<String>();
// check to see if there is anything there
if (this.originalWord != null && !this.originalWord.isEmpty())
{
String lowered = this.originalWord.toLowerCase();
String[] splits = lowered.split(" ");
if (splits != null)
{
int iSize = splits.length;
if (iSize > 0)
{
// basically create a string
for (int i = 0; i < iSize; i++)
{
splitList.add(splits[i]);
}
}
}
}
return splitList;
}
// helper method to see if we need to add to the count
private void upsertString(String s)
{
if (s != null && !s.isEmpty())
{
if (this.wordCounts != null)
{
// default to 1, if its an insert
Integer newCount = 1;
// if it already exists we want to update
if (this.wordCounts.containsKey(s))
{
Integer currentCount = this.wordCounts.get(s);
if (currentCount != null)
{
// update the count by 1
newCount += currentCount;
}
}
// insert the new item
// or overwrite, because it is the same key to the new count
this.wordCounts.put(s, newCount);
}
}
}
public String getOriginalWord()
{
return this.originalWord;
}
public void setOriginalWord(String originalWord)
{
this.originalWord = originalWord;
}
public Set<String> getDistinctWords()
{
return this.distinctWords;
}
public void setDistinctWords(Set<String> distinctWords)
{
this.distinctWords = distinctWords;
}
public Map<String, Integer> getWordCounts()
{
return this.wordCounts;
}
public void setWordCounts(Map<String, Integer> wordCounts)
{
this.wordCounts = wordCounts;
}
}

String Pathing BFS

I am trying to find the shortest path between two strings, and return an int of how many steps were taken. Given that I have a HashMap in which each String(key) has a String[](object) containing all of that strings neighbours.
This code is what I whipped up. I just took a basic BFS and tried to copy that, but I can't quite figure out a way to progress.
public class Main {
private static HashMap<String, String[]> list;
private static int makePath(String from, string to) {
int path = 0;
PriorityQueue<String> queue = new PriorityQueue<>();
queue.add(from);
while (!queue.isEmpty()) {
String u = queue.poll();
if (u == to) {
return path;
}
else {
for (String r : list.get(u)) {
...
}
return path;
}
}
return 0;
}
}
This is just an example of what my HashMap might look like:
Goat, adj[] {Fish, Cow, Chicken}
Cow, adj[] {Pig, Pigeon}
Fish, adj[] {Goat, Bulbasaur, Dolphin, Eagle}
From Fish to Cow I need two steps. From Fish to Goat and Goat to Fish.
So if you got any ideas feel free to share :)
I am thinking of using 2 Queues. I will enqueue the from word to the firstQueue, and while firstQueue is not empty, I will perform an alternating logic to store the neighbors in the other queue if that neighbor is still not equal to to.
It'll be clearer if I give the code,
private static int makePath(final HashMap<String, String[]> tree, final String from, final String to) {
int path = 0;
Queue<String> firstQueue = new PriorityQueue<>();
Queue<String> secondQueue = new PriorityQueue<>();
firstQueue.add(from);
while (!firstQueue.isEmpty()) {
String key = firstQueue.poll();
String[] neighbors = tree.get(key);
if (neighbors != null) {
path++;
for (String neighbor : neighbors) {
if (neighbor.equals(to)) {
return path;
} else {
secondQueue.add(neighbor);
}
}
}
while (!secondQueue.isEmpty()) {
key = secondQueue.poll();
neighbors = tree.get(key);
if (neighbors != null) {
path++;
for (String neighbor : neighbors) {
if (neighbor.equals(to)) {
return path;
} else {
firstQueue.add(neighbor);
}
}
}
}
}
return 0;
}

Categories