Skip to content

Commit cc10173

Browse files
authored
feat: add solutions to lc problem: No.3093 (doocs#2497)
No.3093.Longest Common Suffix Queries
1 parent 5f579e6 commit cc10173

File tree

7 files changed

+724
-75
lines changed

7 files changed

+724
-75
lines changed

solution/3000-3099/3093.Longest Common Suffix Queries/README.md

+247-26
Original file line numberDiff line numberDiff line change
@@ -68,71 +68,292 @@
6868

6969
## 解法
7070

71-
### 方法一
71+
### 方法一:字典树
72+
73+
题目需要我们找到最长公共后缀,我们可以考虑使用字典树。
74+
75+
我们定义字典树的节点结构如下:
76+
77+
- `children`:一个长度为 26 的数组,用于存储子节点。
78+
- `length`:当前节点的最短字符串长度。
79+
- `idx`:当前节点的字符串下标。
80+
81+
我们遍历字符串数组 `wordsContainer`,将每个字符串倒序插入字典树中。在插入的过程中,我们更新每个节点的 `length``idx`
82+
83+
接下来,我们遍历字符串数组 `wordsQuery`,对于每个字符串,我们从字典树中查找最长公共后缀的字符串下标,在寻找的过程中,如果遇到空节点,说明往后没有公共后缀了,我们可以直接返回当前节点的 `idx`
84+
85+
时间复杂度 $(L_1 \times |\Sigma| + L_2)$,空间复杂度 $O(L_1 \times |\Sigma|)$,其中 $L_1$ 和 $L_2$ 分别是 `wordsContainer``wordsQuery` 的字符串长度之和;而 $\Sigma$ 是字符集大小,本题中 $\Sigma = 26$。
7286

7387
<!-- tabs:start -->
7488

7589
```python
7690
class Trie:
7791
__slots__ = ("children", "length", "idx")
7892

79-
def __init__(self, length=inf, idx=inf):
93+
def __init__(self):
8094
self.children = [None] * 26
81-
self.length = length
82-
self.idx = idx
95+
self.length = inf
96+
self.idx = inf
8397

8498
def insert(self, w: str, i: int):
8599
node = self
86-
for c in w:
100+
if node.length > len(w):
101+
node.length = len(w)
102+
node.idx = i
103+
for c in w[::-1]:
87104
idx = ord(c) - ord("a")
88-
if not node.children[idx]:
105+
if node.children[idx] is None:
89106
node.children[idx] = Trie()
90107
node = node.children[idx]
91108
if node.length > len(w):
92109
node.length = len(w)
93110
node.idx = i
94-
elif node.length == len(w):
95-
node.idx = min(node.idx, i)
96111

97-
def query(self, w: str):
112+
def query(self, w: str) -> int:
98113
node = self
99-
ans = node.idx
100-
for c in w:
114+
for c in w[::-1]:
101115
idx = ord(c) - ord("a")
102-
if not node.children[idx]:
116+
if node.children[idx] is None:
103117
break
104118
node = node.children[idx]
105-
ans = node.idx
106-
return ans
119+
return node.idx
107120

108121

109122
class Solution:
110123
def stringIndices(
111124
self, wordsContainer: List[str], wordsQuery: List[str]
112125
) -> List[int]:
113-
k = 0
114-
for i, w in enumerate(wordsContainer):
115-
if len(w) < len(wordsContainer[k]):
116-
k = i
117-
trie = Trie(len(wordsContainer[k]), k)
126+
trie = Trie()
118127
for i, w in enumerate(wordsContainer):
119-
trie.insert(w[::-1], i)
120-
ans = []
121-
for i, w in enumerate(wordsQuery):
122-
ans.append(trie.query(w[::-1]))
123-
return ans
128+
trie.insert(w, i)
129+
return [trie.query(w) for w in wordsQuery]
124130
```
125131

126132
```java
127-
133+
class Trie {
134+
private final int inf = 1 << 30;
135+
private Trie[] children = new Trie[26];
136+
private int length = inf;
137+
private int idx = inf;
138+
139+
public void insert(String w, int i) {
140+
Trie node = this;
141+
if (node.length > w.length()) {
142+
node.length = w.length();
143+
node.idx = i;
144+
}
145+
for (int k = w.length() - 1; k >= 0; --k) {
146+
int idx = w.charAt(k) - 'a';
147+
if (node.children[idx] == null) {
148+
node.children[idx] = new Trie();
149+
}
150+
node = node.children[idx];
151+
if (node.length > w.length()) {
152+
node.length = w.length();
153+
node.idx = i;
154+
}
155+
}
156+
}
157+
158+
public int query(String w) {
159+
Trie node = this;
160+
for (int k = w.length() - 1; k >= 0; --k) {
161+
int idx = w.charAt(k) - 'a';
162+
if (node.children[idx] == null) {
163+
break;
164+
}
165+
node = node.children[idx];
166+
}
167+
return node.idx;
168+
}
169+
}
170+
171+
class Solution {
172+
public int[] stringIndices(String[] wordsContainer, String[] wordsQuery) {
173+
Trie trie = new Trie();
174+
for (int i = 0; i < wordsContainer.length; ++i) {
175+
trie.insert(wordsContainer[i], i);
176+
}
177+
int n = wordsQuery.length;
178+
int[] ans = new int[n];
179+
for (int i = 0; i < n; ++i) {
180+
ans[i] = trie.query(wordsQuery[i]);
181+
}
182+
return ans;
183+
}
184+
}
128185
```
129186

130187
```cpp
131-
188+
class Trie {
189+
private:
190+
const int inf = 1 << 30;
191+
Trie* children[26];
192+
int length = inf;
193+
int idx = inf;
194+
195+
public:
196+
Trie() {
197+
for (int i = 0; i < 26; ++i) {
198+
children[i] = nullptr;
199+
}
200+
}
201+
202+
void insert(string w, int i) {
203+
Trie* node = this;
204+
if (node->length > w.length()) {
205+
node->length = w.length();
206+
node->idx = i;
207+
}
208+
for (int k = w.length() - 1; k >= 0; --k) {
209+
int idx = w[k] - 'a';
210+
if (node->children[idx] == nullptr) {
211+
node->children[idx] = new Trie();
212+
}
213+
node = node->children[idx];
214+
if (node->length > w.length()) {
215+
node->length = w.length();
216+
node->idx = i;
217+
}
218+
}
219+
}
220+
221+
int query(string w) {
222+
Trie* node = this;
223+
for (int k = w.length() - 1; k >= 0; --k) {
224+
int idx = w[k] - 'a';
225+
if (node->children[idx] == nullptr) {
226+
break;
227+
}
228+
node = node->children[idx];
229+
}
230+
return node->idx;
231+
}
232+
};
233+
234+
class Solution {
235+
public:
236+
vector<int> stringIndices(vector<string>& wordsContainer, vector<string>& wordsQuery) {
237+
Trie* trie = new Trie();
238+
for (int i = 0; i < wordsContainer.size(); ++i) {
239+
trie->insert(wordsContainer[i], i);
240+
}
241+
int n = wordsQuery.size();
242+
vector<int> ans(n);
243+
for (int i = 0; i < n; ++i) {
244+
ans[i] = trie->query(wordsQuery[i]);
245+
}
246+
return ans;
247+
}
248+
};
132249
```
133250
134251
```go
252+
const inf = 1 << 30
253+
254+
type Trie struct {
255+
children [26]*Trie
256+
length int
257+
idx int
258+
}
259+
260+
func newTrie() *Trie {
261+
return &Trie{length: inf, idx: inf}
262+
}
263+
264+
func (t *Trie) insert(w string, i int) {
265+
node := t
266+
if node.length > len(w) {
267+
node.length = len(w)
268+
node.idx = i
269+
}
270+
for k := len(w) - 1; k >= 0; k-- {
271+
idx := int(w[k] - 'a')
272+
if node.children[idx] == nil {
273+
node.children[idx] = newTrie()
274+
}
275+
node = node.children[idx]
276+
if node.length > len(w) {
277+
node.length = len(w)
278+
node.idx = i
279+
}
280+
}
281+
}
282+
283+
func (t *Trie) query(w string) int {
284+
node := t
285+
for k := len(w) - 1; k >= 0; k-- {
286+
idx := int(w[k] - 'a')
287+
if node.children[idx] == nil {
288+
break
289+
}
290+
node = node.children[idx]
291+
}
292+
return node.idx
293+
}
294+
295+
func stringIndices(wordsContainer []string, wordsQuery []string) (ans []int) {
296+
trie := newTrie()
297+
for i, w := range wordsContainer {
298+
trie.insert(w, i)
299+
}
300+
for _, w := range wordsQuery {
301+
ans = append(ans, trie.query(w))
302+
}
303+
return
304+
}
305+
```
135306

307+
```ts
308+
class Trie {
309+
private children: Trie[] = new Array<Trie>(26);
310+
private length: number = Infinity;
311+
private idx: number = Infinity;
312+
313+
public insert(w: string, i: number): void {
314+
let node: Trie = this;
315+
if (node.length > w.length) {
316+
node.length = w.length;
317+
node.idx = i;
318+
}
319+
for (let k: number = w.length - 1; k >= 0; --k) {
320+
let idx: number = w.charCodeAt(k) - 'a'.charCodeAt(0);
321+
if (node.children[idx] == null) {
322+
node.children[idx] = new Trie();
323+
}
324+
node = node.children[idx];
325+
if (node.length > w.length) {
326+
node.length = w.length;
327+
node.idx = i;
328+
}
329+
}
330+
}
331+
332+
public query(w: string): number {
333+
let node: Trie = this;
334+
for (let k: number = w.length - 1; k >= 0; --k) {
335+
let idx: number = w.charCodeAt(k) - 'a'.charCodeAt(0);
336+
if (node.children[idx] == null) {
337+
break;
338+
}
339+
node = node.children[idx];
340+
}
341+
return node.idx;
342+
}
343+
}
344+
345+
function stringIndices(wordsContainer: string[], wordsQuery: string[]): number[] {
346+
const trie: Trie = new Trie();
347+
for (let i: number = 0; i < wordsContainer.length; ++i) {
348+
trie.insert(wordsContainer[i], i);
349+
}
350+
const n: number = wordsQuery.length;
351+
const ans: number[] = new Array<number>(n);
352+
for (let i: number = 0; i < n; ++i) {
353+
ans[i] = trie.query(wordsQuery[i]);
354+
}
355+
return ans;
356+
}
136357
```
137358

138359
<!-- tabs:end -->

0 commit comments

Comments
 (0)