master
1#!/usr/bin/env ruby
2
3def assert_equal(expected, actual)
4 raise "expected: #{expected.inspect}, actual: #{actual.inspect}" unless expected == actual
5end
6
7LETTER_DIGIT_MAPPING = {
8 'a' => 2,
9 'b' => 2,
10 'c' => 2,
11 'd' => 3,
12 'e' => 3,
13 'f' => 3,
14 'g' => 4,
15 'h' => 4,
16 'i' => 4,
17 'j' => 5,
18 'k' => 5,
19 'l' => 5,
20 'm' => 6,
21 'n' => 6,
22 'o' => 6,
23 'p' => 7,
24 'q' => 7,
25 'r' => 7,
26 's' => 7,
27 't' => 8,
28 'u' => 8,
29 'v' => 8,
30 'w' => 9,
31 'x' => 9,
32 'y' => 9,
33 'z' => 9,
34}
35
36DIGIT_TO_LETTER = {
37 2 => 'abc',
38 3 => 'def',
39 4 => 'ghi',
40 5 => 'jkl',
41 6 => 'mno',
42 7 => 'pqrs',
43 8 => 'tuv',
44 9 => 'wxyz',
45}
46
47class Node
48 attr_reader :value, :children
49
50 def initialize(value, children = [])
51 @value = value
52 @children = children
53 end
54
55 def inspect
56 "(#{value},#{children.map(&:inspect).join(",")})"
57 end
58end
59
60def trie_from(words)
61 trie = {}
62 words.each do |word|
63 current = trie
64 word.chars.each do |char|
65 current[LETTER_DIGIT_MAPPING[char]] ||= {}
66 current = current[LETTER_DIGIT_MAPPING[char]]
67 end
68 if !current.key?(-1)
69 current[-1] = [word]
70 else
71 current[-1] << word
72 end
73 end
74 return trie
75end
76
77def words_from(trie, digits)
78 return [] if digits.empty?
79 current = trie[digits.shift]
80 return [] if current.nil?
81
82 matches = []
83 until digits.empty?
84 digit = digits.shift
85 current = current[digit]
86 break if current.nil?
87
88 if current.key?(-1)
89 matches << current[-1]
90 end
91 end
92 return matches.flatten
93end
94
95def solution(input_digits, valid_words)
96 trie = trie_from(valid_words)
97 matches = []
98
99 tail = 0
100 until tail == input_digits.length do
101 window = input_digits[0..tail]
102 words = words_from(trie, window)
103 matches << words unless words.empty?
104 tail += 1
105 end
106 return matches.compact
107end
108
109assert_equal [["act"], ["bat"], ["cat"]], solution([2, 2, 8], ["act", "bat", "cat", "acd", "test"])