string - Given a set of words, how can you identify "n" set of letters that will help you make the maximum number of complete words from the original list? -
example:
n = 9
words = {bike, tire, fuel, biker, filter, trike}
output = {b,t,i,k,e,f,u,l,r}
(order of output not important. important note given word foo, 1 not use f,o alphabet, needed f,o,o. similar alphabets treated separately)
what efficient algorithm solve ?
thinking along lines of using frequency of each character not seem much.
edit: updated edited question. see revision history details.
based on comments, 1 has assume (or @ least consider possibility) in fact np-complete problem. until prooves or disprooves actual complexity of problem, here brute-force solution should @ least compute right output.
edit 2.0: shapiro.yaacov pointed out in answer, indeed np-complete
it uses utility class compute combinations of number of letters initial set of words. there n^k combinations of k letters (given initial set of n letters), not "efficient" in sense of polynomial-time solution - not yet clear whether such solution exists @ all.
in order verify output in view of point mentioned in edited question (namely, letters had appear in resulting list appeared in word), used example input words letters repeated:
"bike", "biker", "trike", "beer", deer", "seed", "feed" for input, program prints
0 letters: [], created words: [] 1 letters: [b], created words: [] 2 letters: [b, b], created words: [] 3 letters: [b, b, b], created words: [] 4 letters: [b, e, e, r], created words: [beer] 5 letters: [b, d, e, e, r], created words: [beer, deer] 6 letters: [b, d, e, e, f, r], created words: [beer, deer, feed] 7 letters: [b, d, e, e, f, r, s], created words: [beer, deer, seed, feed] 8 letters: [b, d, e, e, f, i, k, r], created words: [bike, biker, beer, deer, feed] maybe can considered being helpful, maybe starting point or building block others.
import java.math.biginteger; import java.util.arraylist; import java.util.arrays; import java.util.collection; import java.util.collections; import java.util.comparator; import java.util.iterator; import java.util.linkedhashset; import java.util.list; import java.util.nosuchelementexception; import java.util.set; import java.util.treeset; public class maximizewords { public static void main(string[] args) { list<string> words = arrays.aslist( "bike", "biker", "trike", "beer", "deer", "seed", "feed" ); list<character> allletters = new arraylist<character>(alllettersof(words)); (int n=0; n<=8; n++) { combinationiterable<character> combinations = new combinationiterable<character>(n, allletters); list<solution> solutions = new arraylist<solution>(); (list<character> combination : combinations) { collections.sort(combination); solution solution = new solution(words, combination); solutions.add(solution); } solution bestsolution = collections.max(solutions, new comparator<solution>() { @override public int compare(solution s0, solution s1) { return integer.compare( s0.createdwords.size(), s1.createdwords.size()); } }); system.out.println(bestsolution); } } static class solution { list<character> letters; list<string> createdwords; public solution(list<string> words, list<character> letters) { this.letters = letters; this.createdwords = computecreatedwords(words, letters); } @override public string tostring() { return letters.size() + " letters: " + letters + ", created words: " + createdwords; } } private static list<string> computecreatedwords( list<string> words, list<character> letters) { list<string> createdwords = new arraylist<string>(); (string word : words) { if (creates(letters, word)) { createdwords.add(word); } } return createdwords; } private static boolean creates(list<character> letters, string word) { list<character> copy = new arraylist<character>(letters); (int i=0; i<word.length(); i++) { character c = character.valueof(word.charat(i)); if (!copy.remove(c)) { return false; } } return true; } private static list<character> lettersof(string word) { list<character> letters = new arraylist<character>(); (int i=0; i<word.length(); i++) { letters.add(character.valueof(word.charat(i))); } return letters; } private static set<character> alllettersof(iterable<string> words) { set<character> letters = new treeset<character>(); (string word : words) { letters.addall(lettersof(word)); } return letters; } } //============================================================================= // these classes taken https://github.com/javagl/combinatorics /** * class providing iterator on combinations of number * of elements of given set. set s n = |s|, there are n^k * combinations of k elements of set. number of possible * samples when doing sampling replacement. example:<br /> * <pre> * s = { a,b,c }, n = |s| = 3 * k = 2 * m = n^k = 9 * * combinations: * [a, a] * [a, b] * [a, c] * [b, a] * [b, b] * [b, c] * [c, a] * [c, b] * [c, c] * </pre> * * @param <t> type of elements */ final class combinationiterable<t> implements iterable<list<t>> { /** * input elements */ private final list<t> input; /** * sample size */ private final int samplesize; /** * total number of elements iterator provide */ private final int numelements; /** * creates iterable on multisets of * 'samplesize' elements of given array. * * @param samplesize sample size * @param input input elements */ public combinationiterable(int samplesize, list<t> input) { this.samplesize = samplesize; this.input = input; numelements = (int) math.pow(input.size(), samplesize); } @override public iterator<list<t>> iterator() { return new iterator<list<t>>() { /** * element counter */ private int current = 0; /** * indices of elements chosen */ private final int chosen[] = new int[samplesize]; @override public boolean hasnext() { return current < numelements; } @override public list<t> next() { if (!hasnext()) { throw new nosuchelementexception("no more elements"); } list<t> result = new arraylist<t>(samplesize); (int = 0; < samplesize; i++) { result.add(input.get(chosen[i])); } increase(); current++; return result; } /** * increases k-ary representation of selection of * elements one. */ private void increase() { // array of 'chosen' elements set of size n // number represented in k-ary form, // , thus, method nothing else count. // example, when choosing 2 elements of set // n=10, contents of 'chosen' represent // values // 00, 01, 02,... 09, // 10, 11, 12,... 19, // ... // 90, 91, 92, ...99 // each digit indicating index of element // of input array should placed @ // respective position of output array. int index = chosen.length - 1; while (index >= 0) { if (chosen[index] < input.size() - 1) { chosen[index]++; return; } chosen[index] = 0; index--; } } @override public void remove() { throw new unsupportedoperationexception( "may not remove elements combination"); } }; } } /** * utility methods used in combinatorics package */ class utils { /** * utility method computing factorial n! of number n. * factorial of number n n*(n-1)*(n-2)*...*1, or more * formally:<br /> * 0! = 1 <br /> * 1! = 1 <br /> * n! = n*(n-1)!<br /> * * @param n number of factorial should computed * @return factorial, i.e. n! */ public static biginteger factorial(int n) { biginteger f = biginteger.one; (int = 2; <= n; i++) { f = f.multiply(biginteger.valueof(i)); } return f; } /** * magic utility method happens return number of * bits set '1' in given number. * * @param n number bits should counted * @return number of bits '1' in n */ public static int countbits(int n) { int m = n - ((n >> 1) & 033333333333) - ((n >> 2) & 011111111111); return ((m + (m >> 3)) & 030707070707) % 63; } /** * add elements given iterable given collection * * @param <t> type related elements * @param iterable iterable * @param collection collection */ public static <t> void addall( iterable<? extends t> iterable, collection<? super t> collection) { (t t : iterable) { collection.add(t); } } /** * returns elements given iterable list * * @param <t> type related elements * @param iterable iterable * @return list */ public static <t> list<t> aslist(iterable<? extends t> iterable) { list<t> list = new arraylist<t>(); addall(iterable, list); return list; } /** * returns elements given iterable set * * @param <t> type related elements * @param iterable iterable * @return set */ public static <t> set<t> asset(iterable<? extends t> iterable) { set<t> set = new linkedhashset<t>(); addall(iterable, set); return set; } /** * private constructor prevent instantiation */ private utils() { } } (note that, compared initial version, there not has changed in code - basically, instead of using choiceiterable uses combinationiterable. number of combinations much larger number of choices, feasible smaller inputs initial solution).
Comments
Post a Comment