Suppose you have a dictionary that contains valid words.
Given an input string with all spaces removed, determine whether the string is composed of valid words or not.
You can assume the dictionary is a hashtable that provides O(1) lookup.
Some examples:
helloworld-> hello world (valid)
isitniceinhere-> is it nice in here (valid)
zxyy-> invalid
If a string has multiple possible parsings, just return true is sufficient.
The string can be very long. Hence think an algorithm that is both space & time efficient.
Я думаю, что набор всех строк, которые возникают как конкатенация допустимых слов (слов, взятых из конечного словаря), образуют регулярный язык над алфавитом символов. Затем вы можете построить конечный автомат, который принимает именно те строки, которые вам нужны; время вычисления O (n).
Например, пусть словарь состоит из слов {летучая мышь, сумка}. Затем строим следующий автомат: состояния обозначим 0, 1, 2. Ребра: (0,1, b), (1,2, a), (2,0, t), (2,0, g) ; где тройка (x, y, z) означает ребро, ведущее от x к y на входе z. Единственное принимающее состояние - 0. На каждом шаге, при чтении следующего знака ввода, вы должны вычислить набор состояний, которые достижимы на этом входе. Учитывая, что количество состояний в автомате постоянно, это сложность O (n). Что касается сложности пространства, я думаю, вы можете обойтись с O (количеством слов) с подсказкой для построения выше.
В качестве другого примера, со словами {сумка, летучая мышь, булочка, но} автомат будет выглядеть так:
Предположим, что автомат уже построен (время для этого как-то связано с длина и количество слов :-) Теперь мы утверждаем, что время решить, будет ли строка принята автоматом, составляет O (n), где n - длина входной строки. Более формально наш алгоритм выглядит следующим образом:
Теперь выполняется столько же выполнений этого цикла, сколько имеется входных символов. Единственное, что нам нужно проверить, это то, что шаги 3 и 5 занимают постоянное время. Учитывая, что размер S и R не больше, чем количество состояний в автомате, которое является постоянным, и что мы можем хранить ребра таким образом, чтобы время поиска было постоянным, это следует. (Обратите внимание, что мы, конечно, теряем несколько «синтаксических анализов», но это также не было обязательным требованием.) Я думаю, что это на самом деле называется проблемой членства для обычных языков, но я не смог найти подходящую онлайн-ссылку.
Я бы выбрал рекурсивный алгоритм с неявным отслеживанием с возвратом. Сигнатура функции: f: input -> result
, где input
является строкой, result
либо true
, либо false
] в зависимости от того, может ли вся строка быть токенизирована правильно.
Работает следующим образом:
input
является пустой строкой, вернуть true
. input
(т. Е. На первый символ). Если он есть в словаре, запустите f
с суффиксом input
. Если это вернет истину
, верните также истину
. f
на предыдущем шаге вернул false
, сделайте префикс длиннее на единицу и повторите на шаге 2. Если префикс больше не может быть создан (уже в конце строки), верните false
. Для словарей с небольшим или умеренным количеством неоднозначных префиксов этот должен обеспечить довольно хорошее время работы на практике (O (n) в среднем случае, я бы сказал), хотя теоретически, патологические случаи со сложностью O (2 ^ n), вероятно, могут быть построены. Однако я сомневаюсь, что мы можем добиться большего, поскольку нам в любом случае нужен возврат с возвратом, поэтому «инстинктивный» подход O (n) с использованием обычного предварительно вычисляемого лексера не может быть и речи. ...Я думаю.
РЕДАКТИРОВАТЬ: оценка средней сложности, вероятно, неверна, см. Мой комментарий.
Сложность пространства будет равняться только пространству стека, поэтому O (n) даже в худшем случае.