Skip to content

Commit 4c60fa7

Browse files
geeksforgeeks: add auto-complete feature
1 parent e49a70c commit 4c60fa7

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Auto-complete feature
2+
3+
We are given a Trie with a set of strings stored in it.
4+
Now the user types in a prefix of his search query,
5+
we need to give him all recommendations to auto-complete his query based on the strings stored in the Trie.
6+
7+
## Copyright Notice
8+
9+
This problem is based on [content](https://www.geeksforgeeks.org/auto-complete-feature-using-trie/)
10+
from [GeeksforGeeks](https://www.geeksforgeeks.org)
11+
written by Hemang Sarkar
12+
and subject to [GeeksforGeeks copyright](https://www.geeksforgeeks.org/legal/copyright-information/).
13+
The original content from GeeksforGeeks and any modifications made here are attributed to GeeksforGeeks contributors,
14+
and this work is shared under [CC BY-SA 4.0](../LICENSE).
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package auto_complete_feature
2+
3+
const alphabetSize = 26 + 1
4+
5+
func Solution(q string, dict []string) []string {
6+
if q == "" {
7+
return nil
8+
}
9+
10+
root := newTrieNode()
11+
for _, word := range dict {
12+
root.insert(word)
13+
}
14+
15+
return root.autoComplete(q)
16+
}
17+
18+
type trieNode struct {
19+
childs []*trieNode
20+
isWord bool
21+
isLeaf bool
22+
}
23+
24+
func newTrieNode() *trieNode {
25+
return &trieNode{
26+
childs: make([]*trieNode, alphabetSize),
27+
}
28+
}
29+
30+
func (node *trieNode) insert(s string) {
31+
if len(s) == 0 {
32+
node.isLeaf = true
33+
node.isWord = true
34+
return
35+
}
36+
37+
index := ctoi(rune(s[0]))
38+
child := node.childs[index]
39+
if child == nil {
40+
child = newTrieNode()
41+
node.childs[index] = child
42+
}
43+
44+
child.isLeaf = false
45+
child.insert(s[1:])
46+
}
47+
48+
func (node *trieNode) autoComplete(s string) []string {
49+
next := node
50+
for _, r := range s {
51+
next = next.childs[ctoi(r)]
52+
if next == nil {
53+
return nil
54+
}
55+
}
56+
57+
if next == nil {
58+
return nil
59+
}
60+
61+
return next.append(s)
62+
}
63+
64+
func (node *trieNode) append(s string) []string {
65+
var out []string
66+
if node.isWord {
67+
out = append(out, s)
68+
}
69+
70+
for i, child := range node.childs {
71+
if child == nil {
72+
continue
73+
}
74+
75+
prefix := s + string(itoc(rune(i)))
76+
77+
if child.isLeaf {
78+
out = append(out, prefix)
79+
continue
80+
}
81+
82+
for _, word := range child.append(prefix) {
83+
out = append(out, word)
84+
}
85+
}
86+
87+
return out
88+
}
89+
90+
func itoc(i rune) rune {
91+
switch i {
92+
case 26:
93+
return ' '
94+
default:
95+
return i + 'a'
96+
}
97+
}
98+
99+
func ctoi(c rune) rune {
100+
switch c {
101+
case ' ':
102+
return 26
103+
default:
104+
return c - 'a'
105+
}
106+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package auto_complete_feature_test
2+
3+
import (
4+
"testing"
5+
6+
sut "github.com/minizilla/minmax/geeksforgeeks/auto-complete-feature"
7+
"github.com/minizilla/testr"
8+
)
9+
10+
func TestAutoCompleteFeature(t *testing.T) {
11+
dict := []string{
12+
"i am iron man",
13+
"i am iron man endgame",
14+
"i am iron man meme",
15+
"i am venom",
16+
"i am venom sound",
17+
"i am venom morbius",
18+
"i am batman",
19+
}
20+
21+
tests := map[string]struct {
22+
q string
23+
res []string
24+
}{
25+
"empty": {"", nil},
26+
"can't complete": {"i am man", nil},
27+
"incomplete": {
28+
"i am iro",
29+
[]string{
30+
"i am iron man",
31+
"i am iron man endgame",
32+
"i am iron man meme",
33+
},
34+
},
35+
"incomplete with space": {
36+
"i am venom ",
37+
[]string{
38+
"i am venom morbius",
39+
"i am venom sound",
40+
},
41+
},
42+
"complete": {
43+
"i am batman",
44+
[]string{
45+
"i am batman",
46+
},
47+
},
48+
}
49+
50+
for name, tc := range tests {
51+
t.Run(name, func(t *testing.T) {
52+
assert := testr.New(t)
53+
res := sut.Solution(tc.q, dict)
54+
assert.Equal(res, tc.res)
55+
})
56+
}
57+
}

0 commit comments

Comments
 (0)