Given the string \$s\$. It is required to answer n queries. The \$i\$th query consists of an integer \$k_i\$ and a string \$m_i\$, the answer is the minimum length of the string \$t\$ such that \$t\$ is a substring of \$s\$ and the string \$m_i\$ appears in \$t\$ as a substring at least \$k_i\$ times. A substring of a string is any sequence of consecutive characters in this string. It is guaranteed that for any two queries the strings mi from these queries are different.
Input format: The first line contains the string s \$\left ( 1\leq |s|\leq 10^5 \right )\$. The second line contains the integer n (\$1 n \leq 10^5\$). Each of the next \$n\$ lines contains an integer \$k_i\$ (\$1 \leq k_i \leq |s|\$) and a non-empty string \$m_i\$ - parameters of the request with number \$i\$ . All lines in the input consist only of lowercase letters of the Latin alphabet. The total length of all lines in the input does not exceed \$10^5\$. All \$m_i\$ are different.
Output format: For each request, print the response to it on a separate line. If the string \$m_i\$ occurs s less than \$k_i\$ times, print \$-1\$.
Example:
aaaaa
5
3a
3 aa
2 aaa
3 aaaa
1 aaaaa
Answer:
3
4
4
-1
5
My code:
#include <iostream>
#include <string>
#include <vector>
#include <climits>
using namespace std;
int cntOcc(const string& s, const string& t) {
int cnt = 0;
size_t pos = s.find(t);
while (pos != string::npos) {
cnt++;
pos = s.find(t, pos + 1);
}
return cnt;
}
int minLen(const string& s, const string& t, int k) {
int n = s.size();
int t_len = t.size();
if (cntOcc(s, t) < k) return -1;
int min_len = INT_MAX;
for (int i = 0; i <= n - t_len; ++i) {
int occ = 0;
for (int j = i; j < n; ++j) {
if (s.substr(j, t_len) == t) occ++;
if (occ == k) {
min_len = min(min_len, j - i + t_len);
break;
}
}
}
return min_len == INT_MAX ? -1 : min_len;
}
int main() {
string s;
int n;
cin >> s >> n;
vector<int> k(n);
vector<string> m(n);
for (int i = 0; i < n; ++i) {
cin >> k[i] >> m[i];
}
for (int i = 0; i < n; ++i) {
int res = minLen(s, m[i], k[i]);
cout << res << endl;
}
return 0;
}
The code was quite slow, and I tried to speed it up by using two pointers (two windows) and hashing to count occurrences of the substring
#include <iostream>
#include <string>
#include <vector>
#include <climits>
using namespace std;
int cntOcc(const string& s, const string& t) {
int cnt = 0;
size_t pos = s.find(t);
while (pos != string::npos) {
cnt++;
pos = s.find(t, pos + 1);
}
return cnt;
}
int minLen(const string& s, const string& t, int k) {
int n = s.size();
int t_len = t.size();
if (cntOcc(s, t) < k) return -1;
int l = 0, r = 0;
int occ = 0;
int min_len = INT_MAX;
while (r < n) {
if (s.substr(r, t_len) == t) occ++;
while (occ >= k) {
min_len = min(min_len, r - l + t_len);
if (s.substr(l, t_len) == t) occ--;
l++;
}
r++;
}
return min_len == INT_MAX ? -1 : min_len;
}
int main() {
string s;
int n;
cin >> s >> n;
vector<int> k(n);
vector<string> m(n);
for (int i = 0; i < n; ++i) {
cin >> k[i] >> m[i];
}
for (int i = 0; i < n; ++i) {
int res = minLen(s, m[i], k[i]);
cout << res << endl;
}
return 0;
}
But, the code did not run much faster. It helped, but not significantly. Is there a good code optimization or algorithm for the task?