public List<List<String>> findLadders(String start, String end,
			Set<String> dict) {
		HashMap<String, Queue<String>> adjMap = new HashMap<String, Queue<String>>();// marked the path
		int currLen = 0; //record the shortest Length of ladder
		boolean found = false;
		ArrayList<List<String>> res = new ArrayList<List<String>>();// results
		Queue<String> queue = new LinkedList<String>(); // queue for BFS
		Set<String> unVisited = new HashSet<String>(dict); // unvisited words
		Set<String> visitedThisLev = new HashSet<String>();// check words visited during same level
		unVisited.add(end);

		queue.offer(start);
		int currLev = 1;
		int nextLev = 0;

		for (String word : unVisited) {
			adjMap.put(word, new LinkedList<String>());
		}
		unVisited.remove(start);

		// BFS
		while (!queue.isEmpty()) {
			String currLadder = queue.poll();
			// for all unvisited words that are one character change from current word
			for (String nextLadder : getNextLadder(currLadder, unVisited)) {
				if (visitedThisLev.add(nextLadder)) {
					nextLev++;
					queue.offer(nextLadder);
				}
				adjMap.get(nextLadder).offer(currLadder);//important
				if (nextLadder.equals(end) && !found) {
					found = true;
					currLen += 2;
				}
			}

			if (--currLev == 0) {
				if (found)
					break;
				unVisited.removeAll(visitedThisLev);
				visitedThisLev.clear();
				currLev = nextLev;
				nextLev = 0;
				currLen++;
			}
		}

		if (found) {// find the path
			LinkedList<String> p = new LinkedList<String>();
			p.addFirst(end);
			getLadders(start, end, p, res, adjMap, currLen);
		}

		return res;
	}