#c #string #algorithm #substring
#c #строка #алгоритм #подстрока
Вопрос:
Учитывая строку и подстроку, а также индекс начальной и конечной точек, я хочу иметь возможность находить количество вхождений этой подстроки в привязке. Например, задана строка «ACACTACG», и я хочу найти количество вхождений подстроки «AC» от 3 до 7 (если первый индекс равен 1). Приведенный выше пример выдает результат 2. С 3 по 7 мы имеем «ACTAC», в котором подстрока «AC» встречается 2 раза. Кажется, я не могу закодировать это на C ;
Это проблема C конкурса начинающих AtCoder 122:https://atcoder.jp/contests/abc122/tasks/abc122_c
Мне ДЕЙСТВИТЕЛЬНО УДАЛОСЬ ЭТО ЗАКОДИРОВАТЬ, но лимит времени превышен. Мне нужен более простой подход к этому.
Вот мое представление результата TLE:
#include <iostream>
using namespace std;
int main()
{
int N, Q;
string s;
cin >> N >> Q >> s;
for(int i = 0; i < Q; i )
{
int l, r;
cin >> l >> r;
if(l >= r)
{
cout << 0 << endl;
break;
}
int count = 0;
for(int j = l - 1; j < r; j )
{
if(s[j] == 'A' amp;amp; s[j 1] == 'C' amp;amp; j != r - 1)
{
count ;
j ;
}
}
cout << count << endl;
}
return 0;
}
После выполнения некоторых математических расчетов мне удалось обнаружить, что причина, по которой я получил TLE, заключается в том, что мой код содержит примерно 10 ^ 10 инструкций, в то время как ограничение по времени в 2 секунды способно выполнить только около 2 * 10 ^ 8 инструкций.
Комментарии:
1. Если вы на 100% уверены, что в противном случае код работает безупречно, то, похоже, вам нужен обзор кода, который следует опубликовать на codereview.stackexchange.com . Но, пожалуйста, сначала убедитесь, что вы в теме .
2. Пожалуйста, дайте вашим переменным осмысленные имена, это значительно облегчает чтение и понимание вашего кода, а также снижает риск трудноопределимых ошибок, например, вызванных копипастом, орфографическими ошибками или простым недосмотром из-за того, что такие вещи, как
l
,I
и1
, выглядят похожими.int numberOfFoobars;
намного лучше, чемint N;
.3. Мой плохой. Извините за эти ошибки. Я впервые задаю подобные вопросы, хахах
Ответ №1:
Строка N одинакова для всех запросов, и вы ищете только шаблон AC
. Это означает, что вы можете предварительно вычислить таблицу поиска для ответов и избежать повторения через N для каждого запроса.
В таблице поиска будет указано количество вхождений AC
с начала строки. Для ACACTACG это было бы
A={0,1,1,2,2,2,3,3}
Это помогает, потому что «количество вхождений AC между x и y» совпадает с «количеством вхождений перед y, за исключением тех, которые находятся перед x». Подобные таблицы обычно полезны всякий раз, когда вам приходится отвечать на вопросы о диапазонах
Например, для ответа на запрос 3,7 вы вычисляете A[7]-A[3] = 3-1 = 2.
Комментарии:
1. Сработало как по волшебству! Спасибо за помощь.
Ответ №2:
Как сказал Джони, вы можете создать lookupArr, подобный arr. Поскольку шаблон для сопоставления имеет длину 2, основная идея заключается в:
- Сначала создайте массив длиной n 1, все значения которого будут заполнены 0.
- Во-вторых, когда вы пытаетесь сопоставить шаблон
AC
в строке s, поэтому отметьте 1 в индексеC
в arr, когда вы сопоставляетеAC
в строке. - Таким образом, вы будете выполнять итерацию массива только один раз, прежде чем отвечать на любой запрос
- Для каждого запроса вы можете решить это за O (1) время, поскольку общее количество найденных шаблонов будет равно
arr[r] - arr[l-1]
- Примечание, убедитесь, что вы ищете частичные перекрытия, как описано в приведенном ниже коде
Надеюсь, это поможет:
// This program is created by Ishpreet Singh
#include <iostream>
#include <string>
using namespace std;
int main()
{
int n, q, l, r;
string s;
cin >> n >> q;
cin >> s;
// The lookUp Arr
int arr[n 1];
arr[0] = arr[1] = 0;
for (int i = 1; i < n; i )
{
if (s.at(i - 1) == 'A' amp;amp; s.at(i) == 'C'){
arr[i 1] = arr[i] 1;
}
else{
arr[i 1] = arr[i];
}
}
while (q--)
{
cin >> l >> r;
int ans = arr[r] - arr[l - 1];
// To Remove partial overlaps of AC, like s[l-1] = 'A' and s[l] = 'C'
if (l > 1 amp;amp; arr[l] == arr[l - 1] 1){
ans--;
}
cout << ans << endl;
}
return 0;
}
Таким образом, вы можете отвечать на запросы за O(1)
время, поэтому общая сложность кода будет такой, O(Q)
что он пройдет весь тестовый пример за 1 секунду.
Комментарии:
1. Почему размер массива n 1? Было бы проще, если бы мы могли присвоить arr[0] = 0, тогда,
arr[i] = arr[i - 1] 1
еслиarr[i] = 'C' amp;amp; arr[i] = 'A'
.2. @AhZong Это потому, что строки проиндексированы на 1. Также для случая, когда l = 1
a[r]-a[l-1]
все еще будет сохраняться.