/* * Turn API to private - based on code review * * AddWordToTrieByOneCharATime * function is designed to complete the following tasks: * Add one word in the dictionary to Trie using recursive function * Add one char a time by scanning a word from left to right. * * Tricky part is to set prefix neighbor in the process. * * @index * @charArray * @word - * @neighbor - prefix neighbor, it is empty string if there is no prefix neighbor * * function return: * Tuple<string, string> - string and its prefix neighbor */ private Tuple <string, string> addWordToTrieByOneCharATime( int scanIndex, char[] charArray, string word, string neighbour) { bool isEndOfString = scanIndex == charArray.Length; if (isEndOfString) { IsWord = true; PrefixNeighbor = word; return(new Tuple <string, string>(PrefixNeighbor, neighbour)); } char visiting = charArray[scanIndex]; if (!Children.ContainsKey(visiting)) { Children[visiting] = new TrieWithPrefixNeighbor(); } string updatedNeighbor = IsWord ? PrefixNeighbor : neighbour; // update neighbor string - if IsInDictionary is true, then it is // to set as a prefix neighbor return(Children[visiting].addWordToTrieByOneCharATime( scanIndex + 1, charArray, word, updatedNeighbor)); }
/* * study LINQ - GroupBy * https://msdn.microsoft.com/en-us/library/bb534304(v=vs.110).aspx * * 1. Group string by first char, 26 variations from 'A', 'B', ..., 'Z' * 2. For each group, sort strings by string's length in ascending order * 3. For example, group of strings starting from char 'A', * "A","AB","ACD" * 4. benefit value is to add all chars' ascii value. */ static long Process(string[] dict) { var benefitValue = 0L; var groupped = dict.GroupBy(x => x[0]); // maximum 26 groups, 'A','B', ..., 'Z' foreach (var group in groupped) { // sort by string's length in ascending order var sortedStrings = group.OrderBy(x => x.Length); var trie = new TrieWithPrefixNeighbor(); var banned = new HashSet <string>(); var stack = new Stack <Tuple <string, string> >(); foreach (var word in sortedStrings) { stack.Push(trie.AddWordToTrie(word, "")); } // Enumerate the stack, the longest string will be iterated first. // Maximum independent set is kind of greedy as well. foreach (var tuple in stack) { if (!banned.Contains(tuple.Item1)) { benefitValue += tuple.Item1.ToCharArray().Aggregate(0L, (val, next) => val + (long)next); banned.Add(tuple.Item2); } } } return(benefitValue); }