简体   繁体   中英

How to print out the path taken by the BFS?

I'm working on a problem from Leetcode where we're given a lock combination to reach from the starting combination of 0000. You can only rotate one lock wheel at a time, and you must do it using as few turns as possible. I have my solution to do this, and it works fine, but I don't know how to actually print out the path that the BFS takes to reach this solution (ie the intermediary combinations used to reach it). Any help would be appreciated!

class Solution {

    private static final String START = "0000";

    public int openLock(String[] deadends, String target) {
        if (target == null || target.length() == 0) return -1;
        Set<String> visited = new HashSet<>(Arrays.asList(deadends));
        Queue<String> queue = new LinkedList<>();
        int level = 0;
        queue.offer(START);

        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                String currentLock = queue.poll();
                if (!visited.add(currentLock)) continue;
                if (currentLock.equals(target)) return level;

                for (String nextLock : getNextStates(currentLock)) {
                    if (!visited.contains(nextLock)) queue.offer(nextLock);
                }
            }
            level++;
        }

        return -1;
    }

    private List<String> getNextStates(String lock) {
        List<String> locks = new LinkedList<>();
        char[] arr = lock.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            char c = arr[i];
            arr[i] = c == '9' ? '0' : (char) (c + ((char) 1));
            locks.add(String.valueOf(arr));
            arr[i] = c == '0' ? '9' : (char) (c - ((char) 1));
            locks.add(String.valueOf(arr));
            arr[i] = c;
        }
        return locks;
    }
}

I think you can accomplish it by maintaining child parent relationship.

    Map<String,String> childToParent = new HashMap<String,String>();
    String currentLock = null;
    boolean found = false;
    while (!queue.isEmpty() && !found) {
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            String currentLock = queue.poll();
            if (!visited.add(currentLock)) continue;
            if (currentLock.equals(target)){
                found = true;
                break;
            }
            for (String nextLock : getNextStates(currentLock)) {

                if (!visited.contains(nextLock)){
                   queue.offer(nextLock);
                   childToParent.put(nextLock,currentLock);
                  }
            }
        }
        level++;
    }
    if(!found){
     return -1;
    }
    // Printing path 
    int level = 0;
    while(childToParent.get(currentLock) != null){
        System.out.println(currentLock);
        currentLock = childToParent.get(currentLock);
        level++; 
    }
    System.out.println(currentLock);
    return level;

Like @Tarun said, you can keep a child to parent relationship. There is a better way that I used, but first I'm going to talk about what other problems you have. The first one is you are doing this: Set<String> visited = new HashSet<>(Arrays.asList(deadends)); Arrays.asList(...) in you're case should take in every String in deadends . So, you should change it to this:

HashSet<String> set = new HashSet<>();
for(String s : deadends) {
    set.add(s);
}

Of course rename it to visited , I'm just copy and pasting stuff from my accepted solution. Also, the way you're using Queue is not wrong, but if you're taking everything from it at once and then stuffing new values, might as well use LinkedList or ArrayList . You should take in entries from the Queue one by one, and the Queue puts newer entries later, so you don't have to worry about skipping over things.

The better method for keeping track of the amount of moves you made is storing it into the Queue itself. You store the current combination and the amount of steps taken to get there. So, when you find you're answer, just return the second entry, the number of steps. If you break out of the loop, return -1. Here is my accepted solution using all of that:

class Solution {

    public int openLock(String[] deadends, String target) {
        HashSet<String> set = new HashSet<>();
        for(String s : deadends) {
            set.add(s);
        }

        HashSet<String> visited = new HashSet<>();
        Queue<Pair<String, Integer>> queue = new LinkedList<>();
        queue.offer(new Pair<>("0000", 0));

        while(!queue.isEmpty()) {
            Pair<String, Integer> curr = queue.poll();

            if(set.contains(curr.first) || !visited.add(curr.first)) {
                continue;
            } else if(curr.first.equals(target)) {
                return curr.second;
            } else {
                LinkedList<String> next = next(curr.first);

                for(String s : next) {
                    queue.offer(new Pair<>(s, curr.second + 1));
                }
            }
        }

        return -1;
    }

    private LinkedList<String> next(String string) {
        LinkedList<String> ans = new LinkedList<>();
        ans.add(String.valueOf(new char[]{minus(string.charAt(0)), string.charAt(1), string.charAt(2), string.charAt(3)}));
        ans.add(String.valueOf(new char[]{plus(string.charAt(0)), string.charAt(1), string.charAt(2), string.charAt(3)}));
        ans.add(String.valueOf(new char[]{string.charAt(0), minus(string.charAt(1)), string.charAt(2), string.charAt(3)}));
        ans.add(String.valueOf(new char[]{string.charAt(0), plus(string.charAt(1)), string.charAt(2), string.charAt(3)}));
        ans.add(String.valueOf(new char[]{string.charAt(0), string.charAt(1), minus(string.charAt(2)), string.charAt(3)}));
        ans.add(String.valueOf(new char[]{string.charAt(0), string.charAt(1), plus(string.charAt(2)), string.charAt(3)}));
        ans.add(String.valueOf(new char[]{string.charAt(0), string.charAt(1), string.charAt(2), minus(string.charAt(3))}));
        ans.add(String.valueOf(new char[]{string.charAt(0), string.charAt(1), string.charAt(2), plus(string.charAt(3))}));
        return ans;
    }

    private char minus(char c) {
        return c == '0' ? '9' : (char) ((int) c - 1);
    }

    private char plus(char c) {
        return c == '9' ? '0' : (char) ((int) c + 1);
    }

    private class Pair<E, T> {
        E first;
        T second;

        Pair(E e, T t) {
            first = e;
            second = t;
        }
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM