I am making combinations of 3 different values that give a requested sum, in this case the requested sum is 0.I can't find a way to iterate through a TreeSet with 2 for loops in order to receive a set of 3 numbers without repeating that solution. The third number I would like to obtain by using the contains method of the TreeSet.
This is my code so far, it gives good solutions but it repeats them.
import java.util.*;
public class Tree
{
public static void main(String[] args)
{
TreeSet<Integer> ts = new TreeSet<>();
int array[] = {-5, 1, -4, 6, 2, 3, 9, 5};
int sumSearching = 0;
int valueSearching;
for(int i = 0; i < array.length; i++)
ts.add(array[i]);
for(Integer i: ts)
{
for(Integer j : ts)
{
if(i != j)
{
valueSearching = sumSearching - (i + j);
if(valueSearching != i && valueSearching != j)
if(ts.contains(valueSearching))
System.out.println("Solution: "
+ i + ", " + j + ", " + valueSearching);
}
}
}
}
}
Thanks for any kind of help!
Go for j > i, removing one symmetry.
This does not exclude doubles on {i, j, valueSearching} as negative numbers are involved. So one needs to maintain all solutions.
Set<Set<Integer>> solutions = new HashSet<>();
for (int i: ts)
{
for (int j : ts.tailSet(i, false))
{
valueSearching = sumSearching - (i + j);
if (valueSearching != i && valueSearching != j)
if (ts.contains(valueSearching)) {
Set<Integer> solution = new TreeSet<>();
Collections.addAll(solution, i, j, valueSearching);
if (solutions.add(solution)) {
System.out.println("Solution: "
+ i + ", " + j + ", " + valueSearching);
}
}
}
}
Also note: i != j for Integers should better be i.intValue() != j.intValue() as only in the range -128 .. 127 the object for a number is unique.
Here simply the int primitive type is used, which is more appropriate. Also Set.tailSet(value, exclusive) gives the set after the value. Using an Iterator probably would be more efficient.
Implement a reversable pair class:
class ReversablePair<T>
{
private final T first;
private final T second;
ReversablePair(final T first, final T second)
{
this.first = first;
this.second = second;
}
// Some getters...
#Override
public boolean equals(final Object o)
{
if (o == null) return false;
if (!(o instanceof ReversablePair)) return false;
final ReversablePair that = (ReversablePair) o;
return (this.first.equals(that.first) && this.second.equals(that.second))
|| (this.first.equals(that.second) && this.second.equals(that.first));
}
#Override
public int hashCode()
{
return first.hashCode() + second.hashCode();
}
}
Then maintain a set of previous solutions:
Set<ReversablePair<Integer>> previousSolutions = new HashSet();
And check the set before printing:
if (! previousSolutions.contains(new ReversablePair<>(i, j))
{
// whatever
}
To exclude repeating solutions, it's enough to include only those triples which are in ascending order.
So, try changing this line:
if (valueSearching != i && valueSearching != j)
to:
if (i < j && j < valueSearching)
Related
Need to write an Algo to find Anagram of given string at a given index in lexicographically sorted order. For example:
Consider a String: ABC then all anagrams are in sorted order: ABC ACB
BAC BCA CAB CBA. So, for index 5 value is: CAB. Also, consider the case of duplicates like for AADFS anagram would be DFASA at index 32
To do this I have written Algo but I think there should be something less complex than this.
import java.util.*;
public class Anagram {
static class Word {
Character c;
int count;
Word(Character c, int count) {
this.c = c;
this.count = count;
}
}
public static void main(String[] args) {
System.out.println(findAnagram("aadfs", 32));
}
private static String findAnagram(String word, int index) {
// starting with 0 that's y.
index--;
char[] array = word.toCharArray();
List<Character> chars = new ArrayList<>();
for (int i = 0; i < array.length; i++) {
chars.add(array[i]);
}
// Sort List
Collections.sort(chars);
// To maintain duplicates
List<Word> words = new ArrayList<>();
Character temp = chars.get(0);
int count = 1;
int total = chars.size();
for (int i = 1; i < chars.size(); i++) {
if (temp == chars.get(i)) {
count++;
} else {
words.add(new Word(temp, count));
count = 1;
temp = chars.get(i);
}
}
words.add(new Word(temp, count));
String anagram = "";
while (index > 0) {
Word selectedWord = null;
// find best index
int value = 0;
for (int i = 0; i < words.size(); i++) {
int com = combination(words, i, total);
if (index < value + com) {
index -= value;
if (words.get(i).count == 1) {
selectedWord = words.remove(i);
} else {
words.get(i).count--;
selectedWord = words.get(i);
}
break;
}
value += com;
}
anagram += selectedWord.c;
total--;
}
// put remaining in series
for (int i = 0; i < words.size(); i++) {
for (int j = 0; j < words.get(i).count; j++) {
anagram += words.get(i).c;
}
}
return anagram;
}
private static int combination(List<Word> words, int index, int total) {
int value = permutation(total - 1);
for (int i = 0; i < words.size(); i++) {
if (i == index) {
int v = words.get(i).count - 1;
if (v > 0) {
value /= permutation(v);
}
} else {
value /= permutation(words.get(i).count);
}
}
return value;
}
private static int permutation(int i) {
if (i == 1) {
return 1;
}
return i * permutation(i - 1);
}
}
Can someone help me with less complex logic.
I write the following code to solve your problem.
I assume that the given String is sorted.
The permutations(String prefix, char[] word, ArrayList permutations_list) function generates all possible permutations of the given string without duplicates and store them in a list named permutations_list. Thus, the word: permutations_list.get(index -1) is the desired output.
For example, assume that someone gives us the word "aab".
We have to solve this problem recursively:
Problem 1: permutations("","aab").
That means that we have to solve the problem:
Problem 2: permutations("a","ab").
String "ab" has only two letters, therefore the possible permutations are "ab" and "ba". Hence, we store in permutations_list the words "aab" and "aba".
Problem 2 has been solved. Now we go back to problem 1.
We swap the first "a" and the second "a" and we realize that these letters are the same. So we skip this case(we avoid duplicates).
Next, we swap the first "a" and "b". Now, the problem 1 has changed and we want to solve the new one:
Problem 3: permutations("","baa").
The next step is to solve the following problem:
Problem 4: permutations("b","aa").
String "aa" has only two same letters, therefore there is one possible permutation "aa". Hence, we store in permutations_list the word "baa"
Problem 4 has been solved. Finally, we go back to problem 3 and problem 3 has been solved. The final permutations_list contains "aab", "aba" and "baa".
Hence, findAnagram("aab", 2) returns the word "aba".
import java.util.ArrayList;
import java.util.Arrays;
public class AnagramProblem {
public static void main(String args[]) {
System.out.println(findAnagram("aadfs",32));
}
public static String findAnagram(String word, int index) {
ArrayList<String> permutations_list = new ArrayList<String>();
permutations("",word.toCharArray(), permutations_list);
return permutations_list.get(index - 1);
}
public static void permutations(String prefix, char[] word, ArrayList<String> permutations_list) {
boolean duplicate = false;
if (word.length==2 && word[0]!=word[1]) {
String permutation1 = prefix + String.valueOf(word[0]) + String.valueOf(word[1]);
permutations_list.add(permutation1);
String permutation2 = prefix + String.valueOf(word[1]) + String.valueOf(word[0]);
permutations_list.add(permutation2);
return;
}
else if (word.length==2 && word[0]==word[1]) {
String permutation = prefix + String.valueOf(word[0]) + String.valueOf(word[1]);
permutations_list.add(permutation);
return;
}
for (int i=0; i < word.length; i++) {
if (!duplicate) {
permutations(prefix + word[0], new String(word).substring(1,word.length).toCharArray(), permutations_list);
}
if (i < word.length - 1) {
char temp = word[0];
word[0] = word[i+1];
word[i+1] = temp;
}
if (i < word.length - 1 && word[0]==word[i+1]) duplicate = true;
else duplicate = false;
}
}
}
I think your problem will become a lot simpler if you considerate generating the anagrams in alphabetical order, so you don't have to sort them afterwards.
The following code (from Generating all permutations of a given string) generates all permutations of a String. The order of these permutations are given by the initial order of the input String. If you sort the String beforehand, the anagrams will thus be added in sorted order.
to prevent duplicates, you can simply maintain a Set of Strings you have already added. If this Set does not contain the anagram you're about to add, then you can safely add it to the list of anagrams.
Here is the code for the solution i described. I hope you find it to be simpler than your solution.
public class Anagrams {
private List<String> sortedAnagrams;
private Set<String> handledStrings;
public static void main(String args[]) {
Anagrams anagrams = new Anagrams();
List<String> list = anagrams.permutations(sort("AASDF"));
System.out.println(list.get(31));
}
public List<String> permutations(String str) {
handledStrings = new HashSet<String>();
sortedAnagrams = new ArrayList<String>();
permutation("", str);
return sortedAnagrams;
}
private void permutation(String prefix, String str) {
int n = str.length();
if (n == 0){
if(! handledStrings.contains(prefix)){
//System.out.println(prefix);
sortedAnagrams.add(prefix);
handledStrings.add(prefix);
}
}
else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i + 1, n));
}
}
public static String sort(String str) {
char[] arr = str.toCharArray();
Arrays.sort(arr);
return new String(arr);
}
}
If you create a "next permutation" method which alters an array to its next lexicographical permutation, then your base logic could be to just invoke that method n-1 times in a loop.
There's a nice description with code that can be found here. Here's both the basic pseudocode and an example in Java adapted from that page.
/*
1. Find largest index i such that array[i − 1] < array[i].
(If no such i exists, then this is already the last permutation.)
2. Find largest index j such that j ≥ i and array[j] > array[i − 1].
3. Swap array[j] and array[i − 1].
4. Reverse the suffix starting at array[i].
*/
boolean nextPermutation(char[] array) {
int i = array.length - 1;
while (i > 0 && array[i - 1] >= array[i]) i--;
if (i <= 0) return false;
int j = array.length - 1;
while (array[j] <= array[i - 1]) j--;
char temp = array[i - 1];
array[i - 1] = array[j];
array[j] = temp;
j = array.length - 1;
while (i < j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
return true;
}
I have implemented Sieve of Eratosthenes for finding the list of prime number from 1 to n. My code is working fine for inputs from 1 to 10,000 but I am getting following for values >100,000:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -2146737495
at SieveOfEratosthenes.main(SieveOfEratosthenes.java:53)
I am able to find the issue, which is in the for loop when I am doing i * i as it is going out of Integer range (Integer.MAX_VALUE), but I could not find the solution. Can someone suggest me what changes can be done also I appreciate if someone suggest me any improvement for efficiency in this implementation?
public class SieveOfEratosthenes {
public static void main(String[] args) {
Integer num = Integer.parseInt(args[0]);
Node[] nodes = new Node[num + 1];
for(int i = 1; i < nodes.length; i++) {
Node n = new Node();
n.setValue(i);
n.setMarker(true);
nodes[i] = n;
}
for(int i = 1; i < nodes.length; i++) {
if(nodes[i].getMarker() && nodes[i].getValue() > 1) {
System.out.println("Prime " + nodes[i].getValue());
} else {
continue;
}
for(int j = i * i; j < nodes.length
&& nodes[i].getMarker(); j = j + i) {
nodes[j].setMarker(false);
}
}
System.out.println(l.size());
}
}
class Node {
private int value;
private boolean marker;
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
public void setMarker(boolean marker) {
this.marker = marker;
}
public boolean getMarker() {
return this.marker;
}
public String toString() {
return ("Value : " + marker + " value " + value);
}
}
Essentially, the for(int j = i * i;... loop is to cross out all multiples of i.
It makes sense only to cross out starting from i * i, since all lesser multiples are already crossed out by their lesser divisors.
There are at least two ways to go from here.
First, you can start crossing out from i * 2 instead of i * i.
This will get rid of the overflow.
On the bad side, the complexity of the sieve would grow from O(n log log n) to O(n log n) then.
Second, you can check whether i * i is already too much, and if it is, skip the loop completely.
Recall that it is essentially skipped anyway for i greater than the square root of nodes.length if no overflow occurs.
For example, just add an if (i * 1L * i < nodes.length) before the loop.
for(int i = 1; i < nodes.length; i++) {
if(nodes[i].getMarker() && nodes[i].getValue() > 1) {
System.out.println("Prime " + nodes[i].getValue());
} else {
continue;
}
TO
int limit = 2 << 14;
for(int i = 1; i < nodes.length; i++) {
if(nodes[i].getMarker() && nodes[i].getValue() > 1 && i <= 2 << 15) {
System.out.println("Prime " + nodes[i].getValue());
if (i > limit) {
continue;
}
} else {
continue;
}
I'm using Java, I'm trying to get all the different values from 2d array with recursive function only and without use HashSet ArrayList etc..,
The values will be only [0-9]
i.e:
{{4,2,2,1,4},{4,4,3,1,4},{1,1,4,2,1},{1,4,0,2,2},{4,1,4,1,1}}; -> Returns 5 (Because 4,2,3,1,0)
{{4,6,2,1,4},{4,4,3,1,4},{1,1,4,2,1},{1,4,0,2,2},{4,1,4,1,1}}; -> Returns 6 (Because 4,2,3,1,0,6)
{{4,4,4,4,4}}; -> Returns 1 (4)
What I tried:
public static int numOfColors(int[][] map) {
int colors = 0;
if (map == null || map.length == 0) {
return colors;
} else {
int[] subArr = map[map.length - 1];
for (int i = 0; i < subArr.length; i++) {
int j = i + 1;
for (; j < subArr.length; j++) {
if (subArr[i] == subArr[j]) {
break;
}
}
if (j == subArr.length) {
int k = 0;
for (; k < map.length - 1; k++) {
for (int l = 0; l < map[k].length; l++) {
if (subArr[i] == map[k][l]) {
continue;
}
}
}
if (k == map.length - 1) {
colors++;
}
}
}
int[][] dest = new int[map.length - 1][];
System.arraycopy(map, 0, dest, 0, map.length - 1);
colors += numOfColors(dest);
return colors;
}
}
But this hasn't worked for me, where is the miskate?
Recursion doesn't make much sense here. Just use a simple array as storage, and count the instances of different values, if you know the range (0-9) then a simple int[] will be sufficient.
This should do the trick:
public static int numOfColors(int[][] map){
int[] storage = new int[10];
//iterate through all the values
for(int i = 0; i<map.length; i++){
for(int j = 0; j<map[0].length; j++){
//will throw an Exception if an entry in map is not 0-9
//you might want to check for that
storage[map[i][j]]++;
}
}
int colors = 0;
//now check which values exist.
for(int i = 0; i<storage.length; i++){
if(storage[i] != 0) colors++;
}
return colors;
}
As it was already mentioned by #Cash Lo, you need some kind of storage. So you algorithm could looks something like:
#Test
public void numOfColorsTest() {
int[][] map = new int[][] {{4,2,2,1,4},{4,4,3,1,4},{1,1,4,2,1},{1,4,0,2,2},{4,1,4,1,1}};
System.out.println(String.format("numOfColors: %s", numOfColors(map, new int[0], map.length-1)));
map = new int[][] {{4,6,2,1,4},{4,4,3,1,4},{1,1,4,2,1},{1,4,0,2,2},{4,1,4,1,1}};
System.out.println(String.format("numOfColors: %s", numOfColors(map, new int[0], map.length-1)));
map = new int[][] {{4,4,4,4,4}};
System.out.println(String.format("numOfColors: %s", numOfColors(map, new int[0], map.length-1)));
}
public static int numOfColors(int[][] map, int[] collector, int currentPosition) {
int[] result = collector;
if (currentPosition < 0) {
return collector.length;
}
for (int color : map[currentPosition]) {
boolean found = false;
for (int aResult : result) {
if (aResult == color) {
found = true;
break;
}
}
if (!found) {
int[] newResult = new int[result.length + 1];
System.arraycopy(result, 0, newResult, 0, result.length);
newResult[newResult.length - 1] = color;
result = newResult;
}
}
return numOfColors(map, result, currentPosition-1);
}
I know that this is not the answer but you should always think if your solution makes sense.
In my opinion using recursion here is very bad idea because:
the code isn't readable at all
I haven't checked that but I doubt it's more efficient
recursion is hard to debug
you're making really simple problem complicated
Consider the following code. It does exactly what you need:
Integer[][] array = {{4,2,2,1,4},{4,4,3,1,4},{1,1,4,2,1},{1,4,0,2,2},{4,1,4,1,1}};
int size = Arrays.stream(array)
.flatMap(Arrays::stream)
.collect(Collectors.toSet())
.size();
System.out.println("size = " + size);
If you purposely use recursion in this case the only thing I can recommend is Test Driven Development. Write the algorithm and tests simultaneously.
I have written a program in which you can sort an ArrayList using 3 different sort methods: bubble, merge and bogo (or stupid sort). Here's the code:
import java.util.*;
import java.io.*;
import java.lang.*;
import java.lang.IndexOutOfBoundsException;
public class Sorting {
public static void bubbleSort(ArrayList<Integer> bubble) {
int temp;
if (bubble.size() > 1) {
for (int i = 0; i < bubble.size(); i++) {
for (int j = 0; j < bubble.size() - i - 1; j++) {
if (bubble.get(i).compareTo(bubble.get(i + 1)) > 0) {
temp = bubble.get(i);
bubble.set(i, bubble.get(i + 1));
bubble.set(i + 1, temp);
}
}
}
}
}
public static ArrayList<Integer> mergeSort(ArrayList<Integer> merge) {
if (merge.size() == 1) {
return merge;
} else {
int halfway = merge.size() / 2;
ArrayList<Integer> left = new ArrayList<Integer>(halfway);
ArrayList<Integer> right = new ArrayList<Integer>(merge.size() - halfway);
for (int i = 0; i < halfway; i++) {
left.add(merge.get(i));
}
for (int i = halfway; i < merge.size(); i++) {
right.add(merge.get(i));
}
left = mergeSort(left);
right = mergeSort(right);
ArrayList<Integer> newMerge = new ArrayList<Integer>(merge.size());
int index1 = 0;
int index2 = 0;
for (int i = 0; i < merge.size(); i++) {
if (index1 == left.size()) {
merge.set(i, right.get(index2));
index2++;
} else if (index2 == right.size()) {
merge.set(i, left.get(index1));
index1++;
} else {
if (left.get(index1) <= right.get(index2)) {
newMerge.set(i, left.get(index1));
index1++;
} else if (left.get(index1) >= right.get(index2)) {
newMerge.set(i, right.get(index2));
index2++;
}
}
}
return newMerge;
}
}
public static void bogoSort(ArrayList<Integer> bogo) {
while (!isOrdered(bogo)) {
Collections.shuffle(bogo);
}
}
public static boolean isOrdered(ArrayList<Integer> order) {
for (int i = 0; i < order.size(); i++) {
if (order.get(i) > order.get(i + 1)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
try {
Scanner input = new Scanner(new File("random1.txt"));
ArrayList<Integer> random = new ArrayList<Integer>();
while (input.hasNextInt()) {
random.add(input.nextInt());
}
input.close();
System.out.println("Unsorted: " + random);
long startTime = System.nanoTime();
bubbleSort(random);
long endTime = System.nanoTime();
long duration = ((endTime - startTime) / 1000000);
System.out.println("Sorted: " + random);
System.out.println("Bubble sort took: " + duration + " milliseconds to sort.");
System.out.println();
long startTime2 = System.nanoTime();
mergeSort(random);
long endTime2 = System.nanoTime();
long duration2 = ((endTime2 - startTime2) / 1000000);
System.out.println("Sorted: " + random);
System.out.println("Merge sort took: " + duration2 + " milliseconds to sort.");
System.out.println();
long startTime3 = System.nanoTime();
bogoSort(random);
long endTime3 = System.nanoTime();
long duration3 = ((endTime3 - startTime3) / 1000000);
System.out.println("Sorted: " + random);
System.out.println("Bogo sort took: " + duration3 + " milliseconds to sort.");
System.out.println();
} catch (FileNotFoundException e) {
System.out.println("File is not found.");
System.exit(1);
}
}
}
When I ran the program, the unsorted ArrayList and the bubble sort method showed up but I received an error with my Merge Sort method, which stated that I have an IndexOutOfBoundsException at lines 38, 57 & 102. I did the algorithm correctly but I don't know why I'm receiving an error. Any reasoning behind this?
To List, you can not add or set element, at specific index, if the index is greater than the size. Check the documentation here. You can add null values to your List(newMerge) to fix this or simply add elements to your newMerge list. I prefer later. The other IndexOutOfBoundsException exceptions are related to this.
Corrected Code
public static ArrayList<Integer> mergeSort(ArrayList<Integer> merge) {
if (merge.size() == 1) {
return merge;
} else {
int halfway = merge.size() / 2;
ArrayList<Integer> left = new ArrayList<Integer>(halfway);
ArrayList<Integer> right = new ArrayList<Integer>(merge.size() - halfway);
for (int i = 0; i < halfway; i++) {
left.add(merge.get(i));
}
for (int i = halfway; i < merge.size(); i++) {
right.add(merge.get(i));
}
left = mergeSort(left);
right = mergeSort(right);
int index1 = 0;
int index2 = 0;
// Merge left and right sub-lists into original list
// See how the newMerge list is no longer needed
for (int i = 0; i < merge.size(); i++) {
if (index1 == left.size()) {
merge.set(i, right.get(index2));
index2++;
} else if (index2 == right.size()) {
merge.set(i, left.get(index1));
index1++;
} else {
if (left.get(index1) <= right.get(index2)) {
merge.set(i, left.get(index1)); // We now set the values into merge
index1++;
} else if (left.get(index1) >= right.get(index2)) {
merge.set(i, right.get(index2)); // We now set the values into merge
index2++;
}
}
}
return merge; // We now return a reference to merge, not newMerge
}
}
public static boolean isOrdered(ArrayList<Integer> order) {
for (int i = 0; i < order.size() - 1; i++) { // order.size() - 1 prevents going out of bounds
if (order.get(i) > order.get(i + 1)) {
return false;
}
}
return true;
}
Elaboration
Issues with mergeSort()
The issue arises when you begin merging your left and right sub-lists. Note that during the merging process you invoke the set() method on both the newMerge and merge lists. This isn't what you want. Within the "merge"-loop you may attempt to set a value into the newMerge list when it is empty, or when i is greater than its size. This is the reason for the error you're getting. Since your other sorts seem to sort the original list that was passed in (versus creating a copy, sorting, and returning the copy instead) I can assume your merge sort was intended to do the same. If that's the case, there isn't actually a need for a newMerge list at all, since we can just write into the original merge list. This change can be seen in the code above.
Issues with isOrdered()
Minor issue here. You should have terminated your loop when i == order.size() - 1, not when i == order.size(). Otherwise, when i == order.size() - 1, order.get(i + 1) will attempt to retrieve an element that does not exist within the list (i.e. out of bounds).
I did the algorithm correctly but I don't know why I'm receiving an error.
Clearly, you haven't done the algorithm correctly, or you wouldn't be getting the exception. ;-)
You are calling:
merge.set(i, right.get(index2));
and
merge.set(i, left.get(index1));
which is modifying the original list, not your newly created newMerge list which is returned from mergeSort. The caller expects the returned list to have as many elements as it was passed, but (since it is never modified) it actually has zero, which results in the exception in the caller.
Use newMerge as the target of your set calls, and use add instead of trying to set at a particular index.
I've got this piece of java code:
int maxDigit = 4;
for(int a = 0; a <= maxDigit; a++)
{
for(int b = 0; b <= maxDigit; b++)
{
if(b != a){
for(int c = 0; c <= maxDigit; c++)
{
if(c != a && c != b)
{
for(int d = 0; d <= maxDigit; d++)
{
if(d != a && d != b && d != c)
{
for(int e = 0; e <= maxDigit; e++)
{
if(e != a && e != b && e != c && e != d)
{
String temp = a + "" + b + "" + c + "" + d + "" + e;
System.out.println(temp);
permutations.add(Integer.parseInt(temp));
}
}
}
}
}
}
}
}
}
How can you transform this piece of code into a function?
The purpose is to generate permutations of the digits 0 to 9 and here in the code above it is from 0 to 4. And it seems easy to put it in a function but i couldn't find it immediately.
This is a variant of the classic problem of getting all permutations of a string.
The induction your professor wants you to make is that this problem lends itself well to a solution that uses recursion.
The basic algorithm for the permutations of string s is as follows:
Select the first item in s.
Get all permutations of the other items in s (except the item selected).
Prepend selected item to each permutation from step 2.
Repeat for the next character of s.
Here's an efficient solution using the Functional Java library.
Import these...
import fj.F;
import fj.P2;
import fj.P1;
import fj.data.Stream;
import static fj.data.Stream.nil;
import static fj.data.Stream.cons;
import static fj.data.Stream.range;
import static fj.data.Enumerator.charEnumerator;
import static fj.data.Show.streamShow;
import static fj.data.Show.charShow;
import static fj.P2.map2_;
A recursive function to find permutations:
public Stream<Stream<Character>> permutations(final Stream<Character> s) {
return selections(s).bind(
new F<P2<Character, Stream<Character>>, Stream<Stream<Character>>>() {
public Stream<Stream<Character>>()
f(final P2<Character, Stream<Character>> ys) {
return permutations(ys._2()).bind(cons(ys._1()));
}
});
}
A recursive function to select each element in turn:
public Stream<P2<Character, Stream<Character>>>
selections(final Stream<Character> s) {
if (xs.isEmpty())
return nil();
else {
final char x = xs.head();
final Stream<Character> xs = s.tail()._1();
return cons(P.p(x, xs),
new P1<Stream<P2<Character, Stream<Character>>>>() {
public Stream<P2<Character, Stream<Character>>> _1() {
return selections(xs).map(map2_().f(cons(x))));
}
});
}
}
and then, to get all permutations of characters '0' through '9':
Show<Stream<Character>> s = streamShow(charShow);
for (Stream<Character> ps : permutations(range(charEnumerator, '0', '9'))) {
System.out.println(s.showS(ps));
}
EDIT: This is actually a great use case for comonads. Using the latest trunk head of Functional Java, you can do this with the Zipper comonad, like so:
public static Stream<Stream<Character>> perms(Stream<Character> s) {
Stream<Stream<Character>> r = single(Stream.<Character>nil());
for (final Zipper<Character> z : fromStream(s))
r = join(z.cobind(
new F<Zipper<Character>, Stream<Stream<Character>>>() {
public Stream<Stream<Character>> f(final Zipper<Character> zp) {
return perms(zp.lefts().reverse().append(zp.rights())).map(compose(
Stream.<Character>cons().f(zp.focus()),
P.<Stream<Character>>p1()));
}
}).toStream());
return r;
}
Fill the holes:
int[] indexes = { 0, 0, 0, 0, 0 };
addPermutations(maxDigit, indexes, 0, permutations);
void addPermutations(int max, int[] indexes, int currentIndex, List<Integer> permutations) {
if (currentIndex == indexes.length) {
// terminal case
String temp = ...;
System.out.println(temp);
permutations.add(Integer.parseInt(temp));
} else {
// recursive case
for (int i = 0; i <= max; i++) {
if (... != i) {
indexes[currentIndex] = i;
addPermutations(max, indexes, currentIndex+1, permutations);
}
}
}
}
No code, but an algorithm should be as follows.
Suppose you want all permutations of 5 digits from 0 to 7. To do that:
Calculate j = decimal value of base-7 value of 100000 (1 + 5 zeroes)
Loop for i = 0; i < j; ++i, converting each i to base-7 system, optionally prepending with zeroes.
You could use an N-ary tree, with 4 branches at each point, recursively navigate the tree and step over branches where that node's digit had already been seen?