Skip to content

Instantly share code, notes, and snippets.

@shilad
Created February 10, 2018 20:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save shilad/9d124a855baf92ce800587846f3d7175 to your computer and use it in GitHub Desktop.
Save shilad/9d124a855baf92ce800587846f3d7175 to your computer and use it in GitHub Desktop.
An Iterator that generates all permutations of a string without keeping them in memory.
import java.util.*;
/**
* An Iterator that generates all permutations of a particular string, but
* does not need to store them in memory.
*
* Example usage:
*
* Iterator<String> iter = new StringPermuter("Shilad");
* while (iter.hasNext()) {
* System.out.println("permutation is: " + iter.next());
* }
*
* @author Shilad Sen
*/
public class StringPermuter implements Iterator<String> {
/**
* A Node in the tree of permutation possibilities.
* A Node is represented by a prefix for a permutation, along with some letters
* that have not yet been used.
* A node is terminal (a full permutation) if all letters have been used.
* Children are all possible one character extensions of the prefix by one of
* the unused characters.
*/
private static class Node {
private String prefix;
private String unused;
public Node(String prefix, String unused) {
this.prefix = prefix;
this.unused = unused;
}
public boolean isTerminal() {
return this.unused.isEmpty();
}
public List<Node> children() {
List<Node> result = new ArrayList<Node>();
for (int i = 0; i < unused.length(); i++) {
result.add(new Node(prefix + unused.charAt(i),
unused.substring(0, i) + unused.substring(i+1)));
}
return result;
}
}
private Stack<Node> stack = new Stack<Node>();
public StringPermuter(String letters) {
stack.push(new Node("", letters));
}
public boolean hasNext() {
advance();
return !stack.isEmpty();
}
public String next() {
advance();
if (stack.isEmpty() || !stack.peek().isTerminal()) {
throw new IllegalStateException();
} else {
return stack.pop().prefix;
}
}
// runs the DFS until we get a complete word on the stack
private void advance() {
while (!stack.isEmpty() && !stack.peek().isTerminal()) {
List<Node> children = stack.pop().children();
Collections.reverse(children);
for (Node child : children) {
stack.push(child);
}
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment