-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMultiStringSearch.ts
More file actions
137 lines (107 loc) · 3.66 KB
/
MultiStringSearch.ts
File metadata and controls
137 lines (107 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Solution 1, O(n + s * k * m) time complexity, O(s + k) space complexity,
// where n is the length of the big string, s is the number of small strings,
// k is the sum of occurrences of all characters in the big string
// and m is the length of the longest small string
type CharsPositions = Record<string, number[]>
export function multiStringSearch(bigString: string, smallStrings: string[]) {
const charsPositions: CharsPositions = getCharsPositions(bigString)
const result = new Array(smallStrings.length).fill(false)
for (let i = 0; i < smallStrings.length; i++) {
const firstSmallStringChar = smallStrings[i][0]
if (!charsPositions[firstSmallStringChar]) continue
for (const position of charsPositions[firstSmallStringChar]) {
if (
bigString.slice(position, position + smallStrings[i].length) ===
smallStrings[i]
) {
result[i] = true
break
}
}
}
return result
}
function getCharsPositions(string: string) {
const charsPositions: CharsPositions = {}
for (let i = 0; i < string.length; i++) {
if (!(string[i] in charsPositions)) charsPositions[string[i]] = []
charsPositions[string[i]].push(i)
}
return charsPositions
}
// Solution 2, O(b^2 + ns) time complexity, O(b^2 + n) space complexity,
// where b is the length of the big string, n is the number of small strings
// and s is the length of the longest small string
export function multiStringSearch2(bigString: string, smallStrings: string[]) {
const modifiedSuffixTrie = new ModifiedSuffixTrie(bigString)
return smallStrings.map(string => modifiedSuffixTrie.checkIfContains(string))
}
interface TrieNode {
[key: string]: TrieNode
}
class ModifiedSuffixTrie {
root: TrieNode
constructor(string: string) {
this.root = {}
this.buildModifiedSuffixTrie(string)
}
buildModifiedSuffixTrie(string: string) {
for (let i = 0; i < string.length; i++) {
let currentNode = this.root
for (let j = i; j < string.length; j++) {
if (!currentNode[string[j]]) currentNode[string[j]] = {}
currentNode = currentNode[string[j]]
}
}
}
checkIfContains(string: string) {
let currentNode = this.root
for (const char of string) {
if (!(char in currentNode)) return false
currentNode = currentNode[char]
}
return true
}
}
// Solution 3, O(ns + bs) time complexity, O(ns) space complexity,
// where b is the length of the big string, n is the number of small strings
// and s is the length of the longest small string
export function multiStringSearch3(bigString: string, smallStrings: string[]) {
const { root, endSymbol } = new Trie(smallStrings)
const containedStrings: Record<string, boolean> = {}
for (let i = 0; i < bigString.length; i++) {
if (!(bigString[i] in root)) continue
let currentNode = root
let currIdx = i
while (bigString[currIdx] in currentNode) {
currentNode = currentNode[bigString[currIdx]] as TrieNode2
currIdx++
if (endSymbol in currentNode) {
containedStrings[currentNode[endSymbol] as string] = true
}
}
}
return smallStrings.map(string => string in containedStrings)
}
interface TrieNode2 {
[key: string]: TrieNode2 | string
}
class Trie {
root: TrieNode2
endSymbol: string
constructor(strings: string[]) {
this.root = {}
this.endSymbol = '*'
this.buildTrie(strings)
}
buildTrie(strings: string[]) {
for (const string of strings) {
let currentNode = this.root
for (const char of string) {
if (!(char in currentNode)) currentNode[char] = {}
currentNode = currentNode[char] as TrieNode2
}
currentNode[this.endSymbol] = string
}
}
}