I'm new both to the language, and performance-sensitive algorithms as well, so it's been really challenging so far, which is a good thing I guess.
Anyway, the task was the following:
I have x amount (24 in this case) of
letters, and a
list of words.
I'm supposed to find all the
combinations of words("sentences") that use up the given letters with
no letter remaining.
Update: A word can appear more than once in a sentence, for example "the the the the" is perfectly fine if the letters allow it.
For example:
input:
given letters:
IFSNIHLSTA
And the list of words:
nice
guys
finish
last
(The max amount of words we're looking for is irrelevant in this case.)
The output is:
finish last
last finish
I'm pretty sure there are some existing algorithms I could use, but I don't know any at the moment, so I decided to write one from scratch, and as you could guess, it ended up being so slow that it's unusable.
What I have tried:
The
very first thing to do was obviously to
cut down the amount of words first, so I filtered those out that aren't needed for sure.
Then the first
main idea was to take a word, use the letters up for it, then take a next word, and use the remaining letters, and so on until all the letters are used up, or no more words can be created. If the letters are all used up, then hurray we got a sentence.
Repeating the above process for all the words, and again for each word(after a valid one) will in the end get us all the combinations, right?
The
problem with it
is the speed, finding sentences containing a single word will require iterating through the list once, however two word sentences will need an another iteration after each word in the worst case, and if we're looking for 6 word sentences, then oh boy... you get the idea.
So I looked into ways to make it efficient enough to be usable (if I had been successful, I wouldn't be writing this):
I figured that since I'm only looking for the combinations, the order doesn't matter, so I have far fewer words to start with (if I'm looking for sentences of 6 words, then I only have to look at the 1/6 of the words for the first iteration).
The implementation is really a spaghetti code, as a day ago I didn't even know what python looked like, sorry about it.
Anyway it follows the logic written above, the difference being that it splits the words up, and starts a process for each cpu core.
Since it is around 200 lines, I put it on pastebin instead of pasting it here:
Code on pastebin[
^]
I have 2 kinds of questions:
Theoretical:
How to improve the algorithm, or what other algorithms to use, that could be more efficient? (and also what am I missing?)
Update: There still some duplicates in the output, and I'll need to figure a way out to remove them.
About performance itself:
Even though each process runs on an own cpu thread, and there's no disk i/o going on, the CPUs isn't 100% used, why could that be?
Also would I get further with CUDA or openCL, if yes, how?
Thanks in advance