Skip to content

Commit 572e16a

Browse files
committed
--update : add SuffixTree
1 parent f6d18ed commit 572e16a

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ Collection of interview questions with Unit Tests. Problems includes Data Struct
3434
- [Queue](src/_DataStructures_/Queue)
3535
- [Weave](src/_DataStructures_/Queue/weave)
3636

37+
- [Suffix Tree](src/_DataStructures_/SuffixTree)
38+
39+
3740
### Logical Problems
3841

3942
- [Anagrams](src/_Problems_/anagrams)
+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/* eslint-disable no-plusplus */
2+
/*
3+
Implemented by watching this conceptually video: https://www.youtube.com/watch?v=VA9m_l6LpwI
4+
5+
Suffix for banana are :
6+
banana
7+
anana
8+
nana
9+
ana
10+
na
11+
a
12+
13+
Constructing a suffix tree is O(n*d) where d is length of max string
14+
15+
Searching a suffix of a string is O(d) where d is length of suffix string.
16+
If found then return the index, else return -1
17+
18+
*/
19+
20+
class Node {
21+
constructor(value, isEnd, index) {
22+
this.data = value;
23+
this.isEnd = isEnd;
24+
this.index = index;
25+
this.next = new Map();
26+
}
27+
}
28+
29+
class SuffixTree {
30+
constructor(string) {
31+
this.head = new Node();
32+
this.string = string;
33+
}
34+
35+
constructSuffixTree() {
36+
const { string } = this;
37+
let currentString = '';
38+
for (let i = string.length - 1; i >= 0; i -= 1) {
39+
currentString = string[i] + currentString;
40+
let j = 0;
41+
let currentNode = this.head;
42+
while (j < currentString.length) {
43+
if (!currentNode.next.has(currentString[j])) {
44+
currentNode.next.set(currentString[j], new Node(currentString, true, i));
45+
break;
46+
} else {
47+
let k = 0;
48+
const partialMatchNode = currentNode.next.get(currentString[j]);
49+
const partialMatchString = partialMatchNode.data;
50+
51+
let matchString = '';
52+
while (k < partialMatchString.length && j < currentString.length && partialMatchString[k] === currentString[j]) {
53+
matchString += currentString[j];
54+
k++;
55+
j++;
56+
}
57+
58+
let diffString = '';
59+
while (k < partialMatchString.length) {
60+
diffString += partialMatchString[k];
61+
k++;
62+
}
63+
partialMatchNode.data = matchString;
64+
if (diffString) {
65+
partialMatchNode.next.set(diffString[0], new Node(diffString, true, partialMatchNode.index));
66+
partialMatchNode.isEnd = false;
67+
partialMatchNode.index = null;
68+
}
69+
70+
if (partialMatchNode.next.has(currentString[j])) {
71+
currentNode = partialMatchNode;
72+
} else {
73+
let nextString = '';
74+
while (j < currentString.length) {
75+
nextString += currentString[j];
76+
j++;
77+
}
78+
partialMatchNode.next.set(nextString[0], new Node(nextString, true, i));
79+
break;
80+
}
81+
}
82+
}
83+
}
84+
}
85+
86+
findSubstring(string) {
87+
if (!this.head.next.has(string[0])) {
88+
return -1;
89+
}
90+
91+
let currentNode = this.head.next.get(string[0]);
92+
let currentNodeValue = currentNode.data;
93+
94+
let i = 0; let j = 0;
95+
96+
while (i < string.length) {
97+
j = 0;
98+
while (i < string.length && j < currentNodeValue.length && string[i++] === currentNodeValue[j++]);
99+
100+
if (i === string.length && j === currentNodeValue.length && currentNode.isEnd) {
101+
return currentNode.index;
102+
}
103+
104+
if (currentNode.next.has(string[i])) {
105+
currentNode = currentNode.next.get(string[i]);
106+
currentNodeValue = currentNode.data;
107+
} else {
108+
return -1;
109+
}
110+
}
111+
return -1;
112+
}
113+
}
114+
115+
// const s = new SuffixTree('banana');
116+
// s.constructSuffixTree();
117+
118+
// console.log(s.findSubstring('nana'));
119+
120+
121+
module.exports = SuffixTree;

0 commit comments

Comments
 (0)