Как найти число 010 в определенном диапазоне двоичной строки
Дана двоичная строка. Как найти вхождения "010" в определенном диапазоне строки.
Например, у меня есть строка "0100110". Если заданный диапазон равен 3 7 (индексирование на основе 1), выходной сигнал будет равен 4. Я не мог найти более быстрый способ решить это.
Пытаясь это, я могу решить это в O(N) сложности. Подход заключается в том, чтобы - сначала я укажу положение всех "1" в определенном диапазоне, и, используя эту позицию, я выясню число "0" как вперед, так и вперед. А затем умножьте число "0", найденное в спине, на один "1" с числом "0" в найденном в четверти. Затем суммируйте умноженный результат для каждого из '1' в пределах определенного диапазона.
Для данного примера позиция '1' в пределах диапазона составляет {5, 6}. Теперь для индекса 5 у меня число "0" в обоих направлениях равно 2 и 1 соответственно. Таким образом, мы можем сделать подпоследовательность "010" равной 2. Аналогично для индекса 6 мы также получаем ответ 2. Всего мы можем сделать подпоследовательность "010" всего 4 раза.
Но когда у нас есть несколько Q запросов определенных диапазонов для данной строки, мой подход легко достигает временной сложности O (N2). Я много пробовал, но не смог найти способ его оптимизировать. Кто-нибудь может мне помочь с подходом, который меньше, чем сложность O (N2)? Просто упомянуть, что ограничение по времени должно быть 1 секунда. Это будет плюсом, если вы предоставите псевдокод.
~ Заранее спасибо.
1 ответ
Предварительная обработка: сделать вспомогательный массив, содержащий кумулятивное число нулей до заданной позиции (с aux[0]=0)
0 1 0 0 1 1 0 //string
0 1 1 2 3 3 3 4 //aux array A[]
Для данного L..R
сканирование диапазона для них, для каждого индекса k 1
получить число нулей в диапазоне - O(1) операция
P[k] = (A[k] - A[L-1]) * (A[R] - A[k])
S = Sum(P[k], k=L..R)
Итак, мы имеем O(R-L)
время на запрос и худший случай O(Q*N)
для Q запросов
Но посмотрите на формулу полностью:
P[k] = (A[k] - A[L-1]) * (A[R] - A[k]) =
A[k] * (A[R] + A[L-1]) - A[k]^2 - A[R] * A[L-1] =
A[k] * LRSum - A[k]^2 - LRProd
S = Sum(A[k] for ones) * LRSum - Sum(A[k]^2) - LRProd * NumOfOnes
Обратите внимание, что LRSum
а также LRProd
являются константами для данного запроса, и мы должны вычислить суммы A[k] для позиций единиц и сумму квадратов для тех же позиций. Кажется, мы можем использовать ту же идею кумулятивного массива и получить результат в O(1)
за запрос.
Быстрая проверка дает (3+3)*5 - (9+9) - 4*2 = 30-18-8 = 4
для вашего примера.
Использование накопительных массивов:
0 1 0 0 1 1 0 //string
0 1 1 2 3 3 3 4 //aux array A[]
0 0 1 1 1 4 7 7 //aux array B[]
0 0 1 1 1 10 19 19 //aux array C[]
Result = (B[R] - B[L-1]) * (A[R] + A[L-1]) - (C[R] - C[L-1]) -
A[R] * A[L-1] * (R - L - 1 - (A[R] - A[L-1])) =
(7-1) * (4 + 1) - (19 - 1) - 4 * 1 * (7 - 2 - 4 + 1) = 4