连接词

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
class Solution {
public:
// 存放字符串哈希
unordered_set<unsigned long long> st;
int P = 131, OFFSET = 128;
vector<string> findAllConcatenatedWordsInADict(vector<string> &words) {
// 对每个字符串计算哈希,然后存入 set 里面,后面用来快速判断字符串是否存在
for (auto &s : words) {
unsigned long long hash = 0;
for (auto &c : s) {
hash = hash * P + (c - 'a') + OFFSET;
}
st.insert(hash);
}
vector<string> ans;
// 遍历每个字符串,如果这个字符串是连接词,那么假如答案
for (auto &s : words) {
if (check(s)) {
ans.push_back(s);
}
}
return ans;
}
bool check(string &s) {
int n = s.size();
// 动态规划数组,f[i] 表示考虑 s 的前 i 个字符,最大的能切分出的部分的个数
vector<int> f(n + 1, -1);
f[0] = 0;
for (int i = 0; i <= n; i++) {
if (f[i] == -1) continue;
// cur 存放 s[i + 1, j] 的哈希
unsigned long long cur = 0;
for (int j = i + 1; j <= n; j++) {
cur = cur * P + (s[j - 1] - 'a') + OFFSET;
// 如果 s[i + 1, j] 存在于 words 中
if (st.count(cur)) {
// f[j] 可以从 f[i] 转移过来
f[j] = max(f[j], f[i] + 1);
}
}
if (f[n] > 1) return true;
}
return false;
}
};