The following is based on my mis-reading your post. I'll leave it in to entertain you.
The real solution is at the end of the post.
Are you sure that you want to calculate all possibilities of 5 words from a pool of 700 objects?
Here is my class to solve this problem:
public class SO3206795 {
private static long ct;
private static List<String[]> allPossibleWords(final Set<String> words, final String[] chain) {
final List<String> usedWords = Arrays.asList(chain);
final int offset = usedWords.lastIndexOf(null);
List<String[]> wordsList;
if (offset < 0) {
wordsList = Collections.singletonList(chain);
logCreated();
} else {
wordsList = new ArrayList<String[]>();
for (final String word : words) {
final String[] copy = Arrays.copyOf(chain, chain.length);
if (!usedWords.contains(word)) {
copy[offset] = word;
wordsList.addAll(allPossibleWords(words, copy));
}
}
}
return wordsList;
}
private static List<String[]> getChains(final Set<String> words, final int length) {
final List<String[]> tmpChain = new ArrayList<String[]>();
final String[] chain = new String[length];
tmpChain.addAll(allPossibleWords(words, chain));
return tmpChain;
}
private static Set<String> getWords(final int count, final int letters) {
final Set<String> set = new TreeSet<String>();
final int[] arr = new int[letters];
int tempCt = 0;
while (tempCt++ < count) {
set.add(nextWord(arr));
for (int i = letters - 1; i >= 0; i--) {
if (arr[i] == 25) {
arr[i] = 0;
} else {
arr[i] = arr[i] + 1;
break;
}
}
}
return set;
}
private static void logCreated(){
if(++ct%10000==0){
System.out.println("Created "+ct+" chains");
}
}
public static void main(final String[] args) {
String[]usedArgs=args;
if(args.length==1&&args[0].matches(".*\\D.*")){
usedArgs=args[0].split("\\D+");
};
final int[] values = {10,3,5};
for (int i = 0; i < usedArgs.length&&i<values.length; i++) {
values[i] = Integer.parseInt( usedArgs[i]);
}
final SO3206795 thing = new SO3206795(values[0],values[1],values[2]);
for (final String[] chain : thing.chains) {
System.out.println(Arrays.toString(chain));
}
}
private static String nextWord(final int[] arr) {
final char[] ch = new char[arr.length];
for (int i = 0; i < arr.length; i++) {
final int j = arr[i];
ch[i] = (char) (65 + j);
}
return new String(ch);
}
private static void printInfo(final int numberOfWords, final int wordLength, final int chainLength) {
BigInteger words = BigInteger.valueOf(numberOfWords);
for(int i = 1; i < chainLength; i++){
words=words.multiply(BigInteger.valueOf(numberOfWords-i));
}
System.out.println(MessageFormat.format(
"Creating {0} words of length {1}.\nCreating all possible chains of {2} words.\nThat''s {3} chains in total",
numberOfWords, wordLength, chainLength, words.toString()));
}
Set<String> words;
List<String[]> chains;
public SO3206795(final int numberOfWords, final int wordLength, final int chainLength) {
printInfo(numberOfWords,wordLength, chainLength);
this.words = getWords(numberOfWords, wordLength);
this.chains = getChains(this.words, chainLength);
}
}
It has a main method that you can call with up to three arguments:
- numberOfWords (the number of words that will be generated, default: 10)
- wordLength (word length, default: 3)
- chainLength (length of word chains, default: 5)
However, when I launch it with the values 700, 3, 5, the debug output is this:
Creating 700 words of length 3.
Creating all possible chains of 5 words.
That's 165680980516800 chains in total
That's rather a lot, wouldn't you say so? Well that's what 700 * 699 * 698 * 697 * 696 adds up to. Now if you're using your own objects rather than strings and let's say your objects are just 3 bytes each in size this means you'll have a memory consumption of
497042941550400 Bytes or
485393497607 KB or
474017087 MB or
462907 GB or
452 TB
I don't know about you, but that's way more RAM than my machine has, I'm afraid, and unfortunately it's very unlikely that your objects are only 3 Bytes each (And the created lists and arrays also need some significant memory). So I don't think computing all possibilities is a good idea, even if it was fun to code.
And it will take a long time, too. On my machine, creating 10000 chains takes about 16 ms. So for 165680980516800 chains that's a total duration of
2650895688268 ms or
2650895688 sec or
44181594 min or
736359 hours or
30681 days or
84 years
That's not too long, perhaps, as Deep Thought took 7 1/2 million years to come up with the answer 42, but it's probably still longer than you'll be willing to wait.
Please: my math is awful, if somebody explains to me why this is all nonsense I'll be more than happy, but I am afraid I've got the numbers figured out correctly.
End of misunderstanding:
Darn, I missed the letter linking constraint. Here's my updated solution. Replace the method allPossibleWords above with these two methods:
private static List<String[]> allPossibleWords(final Set<String> words, final String[] chain) {
final List<String> usedWords = Arrays.asList(chain);
final int offset = usedWords.lastIndexOf(null);
List<String[]> wordsList;
if (offset < 0) {
wordsList = Collections.singletonList(chain);
logCreated();
} else {
wordsList = new ArrayList<String[]>();
for (final String word : words) {
if (!usedWords.contains(word)&&(offset==chain.length-1||isLegalNeighbor(word,usedWords.get(offset+1)))) {
final String[] copy = Arrays.copyOf(chain, chain.length);
copy[offset] = word;
wordsList.addAll(allPossibleWords(words, copy));
}
}
}
return wordsList;
}
private static boolean isLegalNeighbor(final String left, final String right) {
return left.charAt(left.length()-1)==right.charAt(0);
}
also, we'll replace getWords with a more random version
private static Set<String> getWords(final int numberOfWords, final int wordLength) {
final Set<String> set=new TreeSet<String>();
final Random r = new Random();
while(set.size()<numberOfWords){
final char[] ch = new char[wordLength];
for (int i = 0; i < ch.length; i++) {
ch[i]=(char) (65+r.nextInt(26));
}
set.add(new String(ch));
}
return set;
}
Now I actually get reasonable execution times for 200 words, but 700 words still creates an OutOfMemoryError after what seems like forever.
Anyway, here is the complete solution on pastebin.
And here is the corrected math:
There are approximately 362559479 possible combinations
700 * (699/26) * (698/26) * (697/26) * (696/26)
given an object size of 3 bytes that means a memory consumption of
1087678437 Bytes or
1062185 KB or
1037 MB or
1 GB
On my machine, creating 10000 chains with letter linking takes about 500 ms.
So for 362559479 chains that's a total duration of
181279739 ms or
181279 sec or
3021 min or
50 hours or
2 days
These are still impressive numbers, I'd say