|
56 | 56 |
|
57 | 57 | ## 解法
|
58 | 58 |
|
59 |
| -### 方法一 |
| 59 | +### 方法一:滑动窗口 + 倒序遍历 |
| 60 | + |
| 61 | +我们可以维护一个长度为 $k$ 的滑动窗口,用来计算子串的哈希值。考虑到如果正序遍历字符串,在哈希值的计算中,涉及到除法取模的操作,处理起来比较麻烦。因此我们可以倒序遍历字符串,这样在计算哈希值的时候,只需要乘法和取模操作。 |
| 62 | + |
| 63 | +我们首先计算字符串末尾的 $k$ 个字符的哈希值,然后从字符串末尾开始倒序遍历,每次计算当前窗口的哈希值,如果等于给定的哈希值,我们就找到了一个满足条件的子串,更新答案字符串的起始位置。 |
| 64 | + |
| 65 | +最后返回答案字符串即可。 |
| 66 | + |
| 67 | +时间复杂度 $O(n)$,其中 $n$ 是字符串的长度。空间复杂度 $O(1)$。 |
60 | 68 |
|
61 | 69 | <!-- tabs:start -->
|
62 | 70 |
|
| 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 | + |
63 | 202 | ```js
|
64 | 203 | /**
|
65 | 204 | * @param {string} s
|
|
70 | 209 | * @return {string}
|
71 | 210 | */
|
72 | 211 | 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); |
76 | 214 | 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 | + } |
87 | 222 | }
|
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; |
93 | 230 | }
|
94 | 231 | }
|
95 |
| - return ans == -1 ? '' : s.substring(ans, ans + k); |
| 232 | + return s.substring(j, j + k); |
96 | 233 | };
|
97 |
| - |
98 |
| -function getCode(str, index) { |
99 |
| - return BigInt(str.charCodeAt(index) - 'a'.charCodeAt(0) + 1); |
100 |
| -} |
101 | 234 | ```
|
102 | 235 |
|
103 | 236 | <!-- tabs:end -->
|
|
0 commit comments