Here is the gist.
Ideally it should take me less than 10 minutes to come out Trie data structure with design, and then go over depth first search, word by word, each word should consider if the first few chars ( 0 - level - 1) should be fixed, which can be looked up in ith column, i's value is level.
When I worked on my first practice yesterday, I did not come out the clear idea illustrated in the following graph. It should be really simple and straightforward.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace _435_word_square | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var list = new List<string>() { "abat", "baba", "atan", "atal" }; | |
var result = WordSquares(list); | |
} | |
public class Trie | |
{ | |
public List<int> Indexes; | |
public Trie[] Children; | |
public Trie() | |
{ | |
Children = new Trie[26]; | |
Indexes = new List<int>(); | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <param name="words"></param> | |
/// <returns></returns> | |
public Trie BuildTrie(List<string> words) | |
{ | |
var root = new Trie(); | |
for (int i = 0; i < words.Count; i++) | |
{ | |
var start = root; | |
var word = words[i]; | |
for(int j = 0; j < word.Count(); j++) | |
{ | |
var next = word[j] - 'a'; | |
if (start.Children[next] == null) | |
{ | |
start.Children[next] = new Trie(); | |
} | |
start = start.Children[next]; | |
start.Indexes.Add(i); | |
} | |
} | |
return root; | |
} | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <param name="words"></param> | |
/// <returns></returns> | |
public static List<List<string>> WordSquares(List<string> words) | |
{ | |
var trie = new Trie(); | |
var root = trie.BuildTrie(words); | |
var length = words[0].Length; | |
var output = new string[length]; | |
var result = new List<List<string>>(); | |
foreach (var word in words) | |
{ | |
output[0] = word; | |
runDFS(words, 1, root, output, result); | |
} | |
return result; | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <param name="words"></param> | |
/// <param name="level"></param> | |
/// <param name="root"></param> | |
/// <param name="output"></param> | |
/// <param name="result"></param> | |
private static void runDFS(List<string> words, int level, Trie root, string[] output, List<List<string>> result) | |
{ | |
if (level >= words[0].Count()) | |
{ | |
result.Add(new List<string>(output)); | |
return; | |
} | |
// baba | |
// a | |
// b | |
// a | |
// The idea is that ith column should be same as ith row for i = 0 to 3 | |
var prefix = ""; | |
for (int i = 0; i < level; i++) | |
{ // level - index | |
prefix += output[i][level].ToString(); // find "a" - level 1 | |
} | |
var start = root; | |
for(int i = 0; i < prefix.Length;i++) | |
{ | |
var next = prefix[i] - 'a'; | |
if (start.Children[next] == null) | |
{ | |
return; | |
} | |
start = start.Children[next]; | |
} | |
foreach (var item in start.Indexes) | |
{ | |
output[level] = words[item]; | |
runDFS( words, level + 1, root, output, result); | |
} | |
} | |
} | |
} |
Here are some highlights:
No comments:
Post a Comment