Skip to content

Commit 551577c

Browse files
authored
feat: add solutions to lc problems: No.2156,3109 (#2568)
* No.2156.Find Substring With Given Hash Value * No.3109.Find the Index of Permutation
1 parent 50c804c commit 551577c

File tree

22 files changed

+1246
-79
lines changed

22 files changed

+1246
-79
lines changed

solution/0400-0499/0438.Find All Anagrams in a String/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,8 @@ function findAnagrams(s: string, p: string): number[] {
364364
if (m < n) {
365365
return ans;
366366
}
367-
const cnt1: number[] = new Array(26).fill(0);
368-
const cnt2: number[] = new Array(26).fill(0);
367+
const cnt1: number[] = Array(26).fill(0);
368+
const cnt2: number[] = Array(26).fill(0);
369369
const idx = (c: string) => c.charCodeAt(0) - 'a'.charCodeAt(0);
370370
for (const c of p) {
371371
++cnt1[idx(c)];

solution/0400-0499/0438.Find All Anagrams in a String/README_EN.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,8 @@ function findAnagrams(s: string, p: string): number[] {
348348
if (m < n) {
349349
return ans;
350350
}
351-
const cnt1: number[] = new Array(26).fill(0);
352-
const cnt2: number[] = new Array(26).fill(0);
351+
const cnt1: number[] = Array(26).fill(0);
352+
const cnt2: number[] = Array(26).fill(0);
353353
const idx = (c: string) => c.charCodeAt(0) - 'a'.charCodeAt(0);
354354
for (const c of p) {
355355
++cnt1[idx(c)];

solution/0400-0499/0438.Find All Anagrams in a String/Solution2.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ function findAnagrams(s: string, p: string): number[] {
55
if (m < n) {
66
return ans;
77
}
8-
const cnt1: number[] = new Array(26).fill(0);
9-
const cnt2: number[] = new Array(26).fill(0);
8+
const cnt1: number[] = Array(26).fill(0);
9+
const cnt2: number[] = Array(26).fill(0);
1010
const idx = (c: string) => c.charCodeAt(0) - 'a'.charCodeAt(0);
1111
for (const c of p) {
1212
++cnt1[idx(c)];

solution/1700-1799/1766.Tree of Coprimes/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565

6666
接下来我们可以使用回溯的方法,从根节点开始遍历整棵树,对于每个节点 $i$,我们可以通过 $f$ 数组得到 $nums[i]$ 的所有互质数。然后我们枚举 $nums[i]$ 的所有互质数,找到已经出现过的且深度最大的祖先节点 $t$,即为 $i$ 的最近的互质祖先节点。这里我们可以用一个长度为 $51$ 的栈数组 $stks$ 来获取每个出现过的值 $v$ 的节点以及其深度。每个栈 $stks[v]$ 的栈顶元素就是最近的深度最大的祖先节点。
6767

68-
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为节点个数。
68+
时间复杂度 $O(n \times M)$,空间复杂度 $O(M^2 + n)$。其中 $n$ 为节点个数,而 $M$ 为 $nums[i]$ 的最大值,本题中 $M = 50$
6969

7070
<!-- tabs:start -->
7171

solution/1700-1799/1766.Tree of Coprimes/README_EN.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,13 @@
5757

5858
## Solutions
5959

60-
### Solution 1
60+
### Solution 1: Preprocessing + Enumeration + Stack + Backtracking
61+
62+
Since the range of $nums[i]$ in the problem is $[1, 50]$, we can preprocess all the coprime numbers for each number and record them in the array $f$, where $f[i]$ represents all the coprime numbers of $i$.
63+
64+
Next, we can use a backtracking method to traverse the entire tree from the root node. For each node $i$, we can get all the coprime numbers of $nums[i]$ through the array $f$. Then we enumerate all the coprime numbers of $nums[i]$, find the ancestor node $t$ that has appeared and has the maximum depth, which is the nearest coprime ancestor node of $i$. Here we can use a stack array $stks$ of length $51$ to get each appeared value $v$ and its depth. The top element of each stack $stks[v]$ is the nearest ancestor node with the maximum depth.
65+
66+
The time complexity is $O(n \times M)$, and the space complexity is $O(M^2 + n)$. Where $n$ is the number of nodes, and $M$ is the maximum value of $nums[i]$, in this problem $M = 50$.
6167

6268
<!-- tabs:start -->
6369

solution/2100-2199/2156.Find Substring With Given Hash Value/README.md

+157-24
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,149 @@
5656

5757
## 解法
5858

59-
### 方法一
59+
### 方法一:滑动窗口 + 倒序遍历
60+
61+
我们可以维护一个长度为 $k$ 的滑动窗口,用来计算子串的哈希值。考虑到如果正序遍历字符串,在哈希值的计算中,涉及到除法取模的操作,处理起来比较麻烦。因此我们可以倒序遍历字符串,这样在计算哈希值的时候,只需要乘法和取模操作。
62+
63+
我们首先计算字符串末尾的 $k$ 个字符的哈希值,然后从字符串末尾开始倒序遍历,每次计算当前窗口的哈希值,如果等于给定的哈希值,我们就找到了一个满足条件的子串,更新答案字符串的起始位置。
64+
65+
最后返回答案字符串即可。
66+
67+
时间复杂度 $O(n)$,其中 $n$ 是字符串的长度。空间复杂度 $O(1)$。
6068

6169
<!-- tabs:start -->
6270

71+
```python
72+
class Solution:
73+
def subStrHash(
74+
self, s: str, power: int, modulo: int, k: int, hashValue: int
75+
) -> str:
76+
h, n = 0, len(s)
77+
p = 1
78+
for i in range(n - 1, n - 1 - k, -1):
79+
val = ord(s[i]) - ord("a") + 1
80+
h = ((h * power) + val) % modulo
81+
if i != n - k:
82+
p = p * power % modulo
83+
j = n - k
84+
for i in range(n - 1 - k, -1, -1):
85+
pre = ord(s[i + k]) - ord("a") + 1
86+
cur = ord(s[i]) - ord("a") + 1
87+
h = ((h - pre * p) * power + cur) % modulo
88+
if h == hashValue:
89+
j = i
90+
return s[j : j + k]
91+
```
92+
93+
```java
94+
class Solution {
95+
public String subStrHash(String s, int power, int modulo, int k, int hashValue) {
96+
long h = 0, p = 1;
97+
int n = s.length();
98+
for (int i = n - 1; i >= n - k; --i) {
99+
int val = s.charAt(i) - 'a' + 1;
100+
h = ((h * power % modulo) + val) % modulo;
101+
if (i != n - k) {
102+
p = p * power % modulo;
103+
}
104+
}
105+
int j = n - k;
106+
for (int i = n - k - 1; i >= 0; --i) {
107+
int pre = s.charAt(i + k) - 'a' + 1;
108+
int cur = s.charAt(i) - 'a' + 1;
109+
h = ((h - pre * p % modulo + modulo) * power % modulo + cur) % modulo;
110+
if (h == hashValue) {
111+
j = i;
112+
}
113+
}
114+
return s.substring(j, j + k);
115+
}
116+
}
117+
```
118+
119+
```cpp
120+
class Solution {
121+
public:
122+
string subStrHash(string s, int power, int modulo, int k, int hashValue) {
123+
long long h = 0, p = 1;
124+
int n = s.size();
125+
for (int i = n - 1; i >= n - k; --i) {
126+
int val = s[i] - 'a' + 1;
127+
h = ((h * power % modulo) + val) % modulo;
128+
if (i != n - k) {
129+
p = p * power % modulo;
130+
}
131+
}
132+
int j = n - k;
133+
for (int i = n - k - 1; i >= 0; --i) {
134+
int pre = s[i + k] - 'a' + 1;
135+
int cur = s[i] - 'a' + 1;
136+
h = ((h - pre * p % modulo + modulo) * power % modulo + cur) % modulo;
137+
if (h == hashValue) {
138+
j = i;
139+
}
140+
}
141+
return s.substr(j, k);
142+
}
143+
};
144+
```
145+
146+
```go
147+
func subStrHash(s string, power int, modulo int, k int, hashValue int) string {
148+
h, p := 0, 1
149+
n := len(s)
150+
for i := n - 1; i >= n-k; i-- {
151+
val := int(s[i] - 'a' + 1)
152+
h = (h*power%modulo + val) % modulo
153+
if i != n-k {
154+
p = p * power % modulo
155+
}
156+
}
157+
j := n - k
158+
for i := n - k - 1; i >= 0; i-- {
159+
pre := int(s[i+k] - 'a' + 1)
160+
cur := int(s[i] - 'a' + 1)
161+
h = ((h-pre*p%modulo+modulo)*power%modulo + cur) % modulo
162+
if h == hashValue {
163+
j = i
164+
}
165+
}
166+
return s[j : j+k]
167+
}
168+
```
169+
170+
```ts
171+
function subStrHash(
172+
s: string,
173+
power: number,
174+
modulo: number,
175+
k: number,
176+
hashValue: number,
177+
): string {
178+
let h: bigint = BigInt(0),
179+
p: bigint = BigInt(1);
180+
const n: number = s.length;
181+
const mod = BigInt(modulo);
182+
for (let i: number = n - 1; i >= n - k; --i) {
183+
const val: bigint = BigInt(s.charCodeAt(i) - 'a'.charCodeAt(0) + 1);
184+
h = (((h * BigInt(power)) % mod) + val) % mod;
185+
if (i !== n - k) {
186+
p = (p * BigInt(power)) % mod;
187+
}
188+
}
189+
let j: number = n - k;
190+
for (let i: number = n - k - 1; i >= 0; --i) {
191+
const pre: bigint = BigInt(s.charCodeAt(i + k) - 'a'.charCodeAt(0) + 1);
192+
const cur: bigint = BigInt(s.charCodeAt(i) - 'a'.charCodeAt(0) + 1);
193+
h = ((((h - ((pre * p) % mod) + mod) * BigInt(power)) % mod) + cur) % mod;
194+
if (Number(h) === hashValue) {
195+
j = i;
196+
}
197+
}
198+
return s.substring(j, j + k);
199+
}
200+
```
201+
63202
```js
64203
/**
65204
* @param {string} s
@@ -70,34 +209,28 @@
70209
* @return {string}
71210
*/
72211
var subStrHash = function (s, power, modulo, k, hashValue) {
73-
power = BigInt(power);
74-
modulo = BigInt(modulo);
75-
hashValue = BigInt(hashValue);
212+
let h = BigInt(0),
213+
p = BigInt(1);
76214
const n = s.length;
77-
let pk = 1n;
78-
let ac = 0n;
79-
// 倒序滑动窗口
80-
for (let i = n - 1; i > n - 1 - k; i--) {
81-
ac = (ac * power + getCode(s, i)) % modulo;
82-
pk = (pk * power) % modulo;
83-
}
84-
let ans = -1;
85-
if (ac == hashValue) {
86-
ans = n - k;
215+
const mod = BigInt(modulo);
216+
for (let i = n - 1; i >= n - k; --i) {
217+
const val = BigInt(s.charCodeAt(i) - 'a'.charCodeAt(0) + 1);
218+
h = (((h * BigInt(power)) % mod) + val) % mod;
219+
if (i !== n - k) {
220+
p = (p * BigInt(power)) % mod;
221+
}
87222
}
88-
for (let i = n - 1 - k; i >= 0; i--) {
89-
let pre = (getCode(s, i + k) * pk) % modulo;
90-
ac = (ac * power + getCode(s, i) - pre + modulo) % modulo;
91-
if (ac == hashValue) {
92-
ans = i;
223+
let j = n - k;
224+
for (let i = n - k - 1; i >= 0; --i) {
225+
const pre = BigInt(s.charCodeAt(i + k) - 'a'.charCodeAt(0) + 1);
226+
const cur = BigInt(s.charCodeAt(i) - 'a'.charCodeAt(0) + 1);
227+
h = ((((h - ((pre * p) % mod) + mod) * BigInt(power)) % mod) + cur) % mod;
228+
if (Number(h) === hashValue) {
229+
j = i;
93230
}
94231
}
95-
return ans == -1 ? '' : s.substring(ans, ans + k);
232+
return s.substring(j, j + k);
96233
};
97-
98-
function getCode(str, index) {
99-
return BigInt(str.charCodeAt(index) - 'a'.charCodeAt(0) + 1);
100-
}
101234
```
102235

103236
<!-- tabs:end -->

0 commit comments

Comments
 (0)