В последнее время я играю в игру на своем iPhone под названием Scramble. Некоторые из вас могут знать эту игру как Boggle. По сути, когда игра начинается, вы получаете матрицу букв примерно так:
F X I E
A M L O
E W B X
A S T U
Цель игры - найти как можно больше слов, которые можно составить, объединив буквы. Вы можете начать с любой буквы, и все буквы, которые ее окружают, являются честной игрой, а затем, как только вы перейдете к следующей букве, все буквы, которые окружают эту букву, являются честной игрой, за исключением любых ранее использованных букв . Таким образом , в приведенном выше сетки, например, я мог придумать слова LOB
, TUX
, SEA
, FAME
и т.д. Слова должны быть не менее 3 -х символов и не более символов NxN, который будет 16 в этой игре , но может изменяться в некоторых реализациях , Хотя эта игра веселая и затягивающая, я, видимо, не очень хорош в ней, и я хотел немного обмануть, создав программу, которая дала бы мне наилучшие слова (чем длиннее слово, тем больше очков вы получаете).
(источник: boggled.org )
Я, к сожалению, не очень хорош с алгоритмами или их эффективностью и так далее. Моя первая попытка использует словарь , такие как этот (~ 2.3MB) и делает линейный поиск пытается соответствовать комбинации с словарных статей. Это занимает очень много времени, чтобы найти возможные слова, и так как вы получаете только 2 минуты за раунд, это просто не подходит.
Мне интересно посмотреть, могут ли какие-либо Stackoverflowers предложить более эффективные решения. Я в основном ищу решения, использующие Big 3 Ps: Python, PHP и Perl, хотя что-нибудь с Java или C ++ тоже круто, так как скорость важна.
ТЕКУЩИЕ РЕШЕНИЯ :
- Адам Розенфилд, Питон, ~ 20 лет
- Джон Фухи, Питон, ~ 3 с
- Кент Фредрик, Perl, ~ 1 с
- Дариус Бэкон, Питон, ~ 1с
- rvarcher, VB.NET (прямая ссылка) , ~ 1с
- Паоло Бергантино, PHP (прямая ссылка) , ~ 5 с (~ 2 с локально)
Ответы:
Мой ответ работает, как и другие, но я опубликую его, потому что он выглядит немного быстрее, чем другие решения Python, от настройки словаря быстрее. (Я проверил это по решению Джона Фухи.) После настройки время, которое нужно решить, уменьшается из-за шума.
Пример использования:
Изменить: отфильтровать слова длиной менее 3 букв.
Редактировать 2: мне было любопытно, почему Perl-решение Кента Фредрика было быстрее; оказывается, что вместо набора символов используется сопоставление с регулярным выражением. То же самое в Python примерно вдвое увеличивает скорость.
источник
def neighbors((x, y))
(насколько я вижу, бессмысленно). Также требуется скобки вокруг аргументаprint
.Самое быстрое решение, которое вы получите, вероятно, будет включать в себя сохранение вашего словаря в три раза . Затем создайте очередь триплетов ( x , y , s ), где каждый элемент в очереди соответствует префиксу s слова, которое может быть записано в сетке и заканчивающемуся в местоположении ( x , y ). Инициализируйте очередь с N x N элементами (где N - размер вашей сетки), по одному элементу для каждого квадрата в сетке. Затем алгоритм работает следующим образом:
Если вы храните свой словарь в дереве, проверка, является ли s + c словом или префиксом слова, может выполняться в постоянное время (при условии, что вы также сохраняете некоторые дополнительные метаданные в каждом элементе данных очереди, такие как указатель на текущий узел в три), поэтому время выполнения этого алгоритма составляет O (количество слов, которые могут быть написаны).
[Edit] Вот реализация в Python, которую я только что написал:
Пример использования:
Вывод:
Примечания: Эта программа не выводит однобуквенные слова и не фильтрует их по длине. Это легко добавить, но не имеет отношения к проблеме. Он также выводит некоторые слова несколько раз, если они могут быть написаны несколькими способами. Если данное слово может быть написано по-разному (наихудший случай: каждая буква в сетке одинакова (например, «A»), а слово типа «aaaaaaaaaa» есть в вашем словаре), тогда время выполнения станет ужасно экспоненциальным , Фильтрация дубликатов и сортировка тривиальны после завершения работы алгоритма.
источник
(x,y)
возможного последователя(x+1,y+1)
. Затем(x+1,y+1)
выталкивается в очередь. Однако(x,y)
тоже будет для вас последователем(x+1,y+1)
, не приведет ли это к бесконечному подпрыгиванию между ними?Для ускорения работы словаря существует одно общее преобразование / процесс, который вы можете сделать, чтобы значительно сократить сравнение словаря заранее.
Учитывая, что приведенная выше сетка содержит только 16 символов, некоторые из которых дублируются, вы можете значительно сократить общее количество ключей в словаре, просто отфильтровывая записи, содержащие недостижимые символы.
Я думал, что это была очевидная оптимизация, но видя, что никто не сделал этого, я упоминаю об этом.
Это уменьшило меня от словаря из 200 000 ключей до всего 2000 ключей просто во время прохода ввода. Это, по крайней мере, уменьшает накладные расходы памяти, и это обязательно приведет к увеличению скорости где-то, поскольку память не бесконечно быстра.
Реализация Perl
Моя реализация немного перегружена, потому что я придавал большое значение тому, чтобы знать точный путь каждой извлеченной строки, а не только ее достоверность.
У меня также есть несколько адаптаций, которые теоретически позволяют сетке с отверстиями в ней функционировать, и сеткам с линиями разных размеров (при условии, что вы правильно вводите данные, и они как-то выстраиваются в линию).
Ранний фильтр, безусловно, является наиболее существенным узким местом в моем приложении, как и предполагалось ранее, комментируя, что эта строка увеличивает его с 1,5 до 7,5 с.
После выполнения кажется, что все отдельные цифры состоят из собственных допустимых слов, но я вполне уверен, что это связано с тем, как работает файл словаря.
Это немного раздутый, но, по крайней мере, я снова использую Tree :: Trie из cpan
Некоторые из них были частично вдохновлены существующими реализациями, некоторые из них я уже имел в виду.
Конструктивная критика и способы ее улучшения приветствуются (/ я отмечает, что он никогда не искал CPAN для решения проблемы , но работать было веселее)
обновлен по новым критериям
Информация об арке / исполнении для сравнения:
Больше бормотаний на этой Оптимизации Regex
Оптимизация регулярных выражений, которую я использую, бесполезна для словарей с несколькими решениями, а для нескольких решений вам понадобится полный словарь, а не предварительно урезанный.
Тем не менее, для одноразовых решений это действительно быстро. (Perl регулярные выражения в C! :))
Вот несколько различных дополнений кода:
пс: 8,16 * 200 = 27 минут.
источник
Вы можете разбить проблему на две части:
В идеале, (2) также должен включать способ проверки, является ли строка префиксом допустимого слова - это позволит вам сократить поиск и сэкономить кучу времени.
Три Адама Розенфилда является решением (2). Это элегантно и, вероятно, то, что предпочитает ваш специалист по алгоритмам, но с современными языками и современными компьютерами мы можем быть немного ленивее. Кроме того, как предполагает Кент, мы можем уменьшить размер нашего словаря, отбрасывая слова, буквы которых отсутствуют в сетке. Вот немного питона:
Ух ты; постоянное тестирование префиксов. Загрузка словаря, на который вы ссылаетесь, занимает пару секунд, но только пару :-) (обратите внимание
words <= prefixes
)Теперь, что касается части (1), я склонен думать в терминах графиков. Поэтому я создам словарь, который выглядит примерно так:
то
graph[(x, y)]
есть набор координат, которые вы можете достичь из позиции(x, y)
. Я также добавлю фиктивный узел,None
который будет соединяться со всем.Создание это немного неуклюже, потому что есть 8 возможных позиций, и вы должны сделать проверку границ. Вот некоторый соответственно неуклюжий код Python:
Этот код также создает словарь сопоставления
(x,y)
с соответствующим символом. Это позволяет мне превратить список позиций в слово:Наконец, мы делаем поиск в глубину. Основная процедура:
Python:
Запустите код как:
и проверить,
res
чтобы увидеть ответы. Вот список слов, найденных для вашего примера, отсортированных по размеру:Код загружает словарь буквально за пару секунд, но на моем компьютере все остальное мгновенно.
источник
range(len(w)+1)
вместоrange(len(w))
. Я утверждал это,words <= prefixes
но, очевидно, я не проверял это: - /Моя попытка в Java. Для считывания файла и построения файла требуется около 2 с, а для решения головоломки - около 50 мс. Я использовал словарь, связанный в вопросе (в нем есть несколько слов, которых я не знал в английском языке, таких как fae, ima)
Исходный код состоит из 6 классов. Я опубликую их ниже (если это не правильная практика в StackOverflow, пожалуйста, сообщите мне).
gineer.bogglesolver.Main
gineer.bogglesolver.Solver
gineer.bogglesolver.trie.Node
gineer.bogglesolver.trie.Trie
gineer.bogglesolver.util.Constants
gineer.bogglesolver.util.Util
источник
Я думаю, что вы, вероятно, потратите большую часть своего времени, пытаясь сопоставить слова, которые не могут быть построены вашей сеткой букв. Итак, первое, что я хотел бы сделать, это попытаться ускорить этот шаг, и это поможет вам пройти большую часть пути.
Для этого я бы повторно выразил сетку в виде таблицы возможных «ходов», которые вы индексируете с помощью буквы-перехода, на которую вы смотрите.
Начните с присвоения каждой букве числа из всего вашего алфавита (A = 0, B = 1, C = 2, ... и т. Д.).
Давайте возьмем этот пример:
А пока давайте используем алфавит букв, которые у нас есть (обычно вы, вероятно, захотите использовать один и тот же целый алфавит каждый раз):
Затем вы создаете двумерный логический массив, который сообщает, есть ли у вас определенный переход букв:
Теперь просмотрите ваш список слов и преобразуйте слова в переходы:
Затем проверьте, разрешены ли эти переходы, посмотрев их в вашей таблице:
Если им всем позволено, есть шанс, что это слово может быть найдено.
Например, слово «шлем» может быть исключено при 4-м переходе (от m до e: helMEt), поскольку эта запись в вашей таблице является ложной.
И слово хомяк может быть исключено, так как первый (h к a) переход недопустим (даже не существует в вашей таблице).
Теперь, для, возможно, очень немногих оставшихся слов, которые вы не исключили, попробуйте найти их в таблице так, как вы это делаете сейчас, или как предложено в некоторых других ответах здесь. Это сделано для того, чтобы избежать ложных срабатываний, возникающих в результате скачков между одинаковыми буквами в вашей сетке. Например, слово «помощь» разрешено таблицей, но не сеткой.
Некоторые дополнительные советы по улучшению производительности по этой идее:
Вместо использования двумерного массива, используйте одномерный массив и просто рассчитайте индекс второй буквы самостоятельно. Таким образом, вместо массива 12x12, как описано выше, создайте одномерный массив длиной 144. Если вы всегда используете один и тот же алфавит (то есть массив 26x26 = 676x1 для стандартного английского алфавита), даже если не все буквы отображаются в вашей сетке Вы можете предварительно вычислить индексы в этом одномерном массиве, который необходимо проверить, чтобы соответствовать словам из словаря. Например, индексы для «привет» в приведенном выше примере будут
Расширьте идею до трехмерной таблицы (представленной в виде одномерного массива), то есть всех допустимых 3-буквенных комбинаций. Таким образом, вы можете сразу исключить еще больше слов и сократить количество поисков в массиве для каждого слова на 1: для «привет» вам нужно только 3 поиска в массивах: hel, ell, llo. Кстати, будет очень быстро построить эту таблицу, поскольку в вашей сетке есть только 400 возможных 3-буквенных ходов.
Предварительно рассчитайте индексы ходов в вашей сетке, которые нужно включить в таблицу. Для приведенного выше примера вам необходимо установить для следующих записей значение «True»:
Я уверен, что если вы воспользуетесь этим подходом, вы сможете заставить свой код работать безумно быстро, если у вас есть предварительно вычисленный словарь и уже загруженный в память.
Кстати, еще одна приятная вещь, если вы создаете игру, - это запускать подобные вещи немедленно в фоновом режиме. Начните генерировать и решать первую игру, пока пользователь все еще смотрит на титульный экран в вашем приложении и вводит палец в положение, чтобы нажать «Play». Затем создайте и решите следующую игру, когда пользователь играет в предыдущую. Это должно дать вам много времени для запуска вашего кода.
(Мне нравится эта проблема, поэтому я, вероятно, буду испытывать желание реализовать свое предложение на Java в ближайшие дни, чтобы посмотреть, как оно на самом деле будет работать ... Я опубликую здесь код, как только это сделаю.)
ОБНОВИТЬ:
Хорошо, у меня было немного времени сегодня и я реализовал эту идею на Java:
Вот некоторые результаты:
Для сетки из картинки, размещенной в оригинальном вопросе (DGHI ...):
Для писем, опубликованных в качестве примера в оригинальном вопросе (FXIE ...)
Для следующей 5x5-сетки:
это дает это:
Для этого я использовал TWL06 Tournament Scrabble Word List , так как ссылка в исходном вопросе больше не работает. Этот файл имеет размер 1,85 МБ, поэтому он немного короче. И
buildDictionary
функция выбрасывает все слова, содержащие менее 3 букв.Вот пара наблюдений о производительности этого:
Это примерно в 10 раз медленнее, чем заявленная производительность реализации OCaml Виктора Николье. Причиной этого является другой алгоритм, более короткий словарь, который он использовал, тот факт, что его код скомпилирован, а мой работает на виртуальной машине Java, или производительность наших компьютеров (у меня Intel Q6600 @ 2,4 МГц с WinXP), Я не знаю. Но это намного быстрее, чем результаты для других реализаций, указанных в конце исходного вопроса. Итак, превосходит ли этот алгоритм словарь Trie или нет, на данный момент я не знаю.
Метод таблицы, используемый в,
checkWordTriplets()
дает очень хорошее приближение к фактическим ответам. Только 1 из 3-5 пропущенных им слов не пройдетcheckWords()
тест (см. Количество кандидатов и количество реальных слов выше).Что-то, чего вы не видите выше:
checkWordTriplets()
функция занимает около 3,65 мс и поэтому полностью доминирует в процессе поиска.checkWords()
Функция занимает довольно много оставшихся 0,05-0,20 мс.Время выполнения
checkWordTriplets()
функции линейно зависит от размера словаря и практически не зависит от размера платы!Время выполнения
checkWords()
зависит от размера доски и количества исключаемых словcheckWordTriplets()
.checkWords()
Реализация выше является тупой первой версией я придумал. Это в основном не оптимизировано вообще. Но по сравнению сcheckWordTriplets()
ним это не имеет значения для общей производительности приложения, поэтому я не беспокоился об этом. Но , если размер платы становится больше, эта функция будет становиться все медленнее и медленнее и в конечном итоге начнет иметь значение. Тогда его тоже нужно оптимизировать.Одна приятная вещь в этом коде - его гибкость:
initializeBoard()
.Хорошо, но я думаю, что этот пост уже достаточно длинный. Я определенно могу ответить на любые ваши вопросы, но давайте перейдем к комментариям.
источник
ok = possibleTriplets[entry.triplets[t]];
. хмм?entry.letters[i] = (byte) letter - 65;
она просто принимает значение ASCII и вычитает 65 («А»). Если в вашем словаре есть Umlauts или строчные буквы, это даст значения больше 31, которые не планируются настройкой размера алфавита в строке 9. Для поддержки других букв вам придется расширить эту строку сопоставить их в диапазоне, разрешенном размером алфавита.Удивительно, но никто не пытался PHP версию этого.
Это рабочая версия PHP решения Джона Фухи на Python.
Хотя я взял некоторые указатели из ответов всех остальных, это в основном скопировано с Джона.
Вот прямая ссылка, если вы хотите попробовать. Хотя на моем локальном компьютере это занимает ~ 2 с, на моем веб-сервере это занимает ~ 5 с. В любом случае это не очень быстро. Тем не менее, это довольно отвратительно, поэтому я могу себе представить, что время можно значительно сократить. Любые указатели о том, как достичь этого, будут оценены. Отсутствие кортежей в PHP сделало координаты странными для работы, и моя неспособность понять, что происходит, черт возьми, не помогла вообще.
РЕДАКТИРОВАТЬ : несколько исправлений сделать это займет менее 1 с локально.
источник
Не заинтересованы в VB? :) Я не мог устоять. Я решил это иначе, чем многие из представленных здесь решений.
Мои времена:
РЕДАКТИРОВАТЬ: время загрузки словаря на сервере веб-хоста работает примерно на 1-1,5 секунды дольше, чем мой домашний компьютер.
Я не знаю, насколько сильно ухудшится время с нагрузкой на сервер.
Я написал свое решение в виде веб-страницы в .Net. myvrad.com/boggle
Я использую словарь, указанный в оригинальном вопросе.
Письма не используются повторно одним словом. Найдены только слова длиной не более 3 символов.
Я использую хеш-таблицу всех уникальных префиксов и слов вместо слова. Я не знал о Три, поэтому я кое-что узнал там. Идея создания списка префиксов слов в дополнение к полным словам - это то, что, наконец, привело к тому, что мое время сократилось до порядочного числа.
Прочитайте комментарии к коду для получения дополнительной информации.
Вот код:
источник
Как только я увидел постановку задачи, я подумал: «Три». Но, учитывая, что несколько других авторов использовали этот подход, я искал другой подход, просто чтобы быть другим. Увы, подход Trie работает лучше. Я запустил решение Perl от Kent на своей машине, и мне потребовалось 0,31 секунды, чтобы адаптировать его для использования файла словаря. Моей собственной реализации на Perl потребовалось 0,54 секунды для запуска.
Это был мой подход:
Создайте хеш перехода для моделирования законных переходов.
Переберите все 16 ^ 3 возможных трехбуквенных комбинаций.
Затем переберите все слова в словаре.
Распечатайте слова, которые я нашел.
Я пробовал трехбуквенные и четырехбуквенные последовательности, но четырехбуквенные последовательности замедляли работу программы.
В моем коде я использую / usr / share / dict / words для своего словаря. Он входит в стандартную комплектацию MAC OS X и многих систем Unix. Вы можете использовать другой файл, если хотите. Чтобы взломать другую головоломку, просто измените переменную @puzzle. Это было бы легко адаптировать для больших матриц. Вам просто нужно изменить хеш% переходов и хеш% legalTransitions.
Сила этого решения в том, что код короткий, а структуры данных простые.
Вот код Perl (который использует слишком много глобальных переменных, я знаю):
источник
Я знаю, что я опоздал, но я сделал это некоторое время назад в PHP - просто для удовольствия ...
http://www.lostsockdesign.com.au/sandbox/boggle/index.php?letters=fxieamloewbxastu Найдено 75 слов (133 балла ) за 0,90108 секунд
F.........X..I..............E............... A......................................M..............................L............................O............................... E....................W............................B..........................X A..................S..................................................T.................U....
Дает некоторое представление о том, что на самом деле делает программа - каждая буква - это то место, где она начинает просматривать шаблоны, а каждая '.' показывает путь, который он пытался пройти. Чем больше '.' есть дальнейшие поиски.
Дайте мне знать, если вам нужен код ... это ужасное сочетание PHP и HTML, которое никогда не предназначалось для того, чтобы увидеть свет, поэтому я не осмелюсь опубликовать его здесь: P
источник
Я потратил 3 месяца, работая над решением проблемы 10x5 Boggle с 10 лучшими точками.
Проблема теперь решена и выложена с полным раскрытием на 5 веб страницах. Пожалуйста, свяжитесь со мной с вопросами.
Алгоритм анализа доски использует явный стек для псевдорекурсивного обхода квадратов доски через направленный ациклический граф слов с прямой дочерней информацией и механизмом отслеживания меток времени. Вполне возможно, что это самая передовая в мире структура данных лексикона.
Схема оценивает около 10 000 очень хороших плат в секунду на четырехъядерном ядре. (9500+ баллов)
Родительская веб-страница:
DeepSearch.c - http://www.pathcom.com/~vadco/deep.html
Веб-страницы компонентов:
Оптимальное табло - http://www.pathcom.com/~vadco/binary.html
Усовершенствованная структура лексики - http://www.pathcom.com/~vadco/adtdawg.html
Алгоритм анализа форума - http://www.pathcom.com/~vadco/guns.html
Параллельная пакетная обработка - http://www.pathcom.com/~vadco/parallel.html
- Эта комплексная работа будет интересна только человеку, который требует самого лучшего.
источник
Ваш алгоритм поиска постоянно уменьшает список слов по мере того, как поиск продолжается?
Например, в приведенном выше поиске есть только 13 букв, с которых ваши слова могут начинаться (эффективно уменьшая вдвое больше начальных букв).
Если вы добавите больше буквенных перестановок, это приведет к дальнейшему уменьшению доступных наборов слов, уменьшая необходимый поиск.
Я бы начал там.
источник
Я должен был бы больше подумать о полном решении, но, как удобная оптимизация, мне интересно, может быть, стоит предварительно рассчитать таблицу частот диграмм и триграмм (двух- и трехбуквенные комбинации) на основе всех слова из вашего словаря, и используйте это, чтобы расставить приоритеты вашего поиска. Я бы пошел с начальными буквами слов. Поэтому, если в вашем словаре содержатся слова «Индия», «Вода», «Экстрим» и «Необыкновенный», то ваша предварительно вычисленная таблица может быть:
Затем найдите эти диграммы в порядке общности (сначала EX, затем WA / IN)
источник
Сначала прочитайте, как один из разработчиков языка C # решил связанную с этим проблему: http://blogs.msdn.com/ericlippert/archive/2009/02/04/a-nasality-talisman-for-the-sultana-analyst.aspx ,
Как и он, вы можете начать со словаря и канонизировать слова, создав словарь из массива букв, отсортированных по алфавиту, в список слов, которые можно записать по этим буквам.
Затем начните создавать возможные слова из доски и искать их. Я подозреваю, что это продвинет вас довольно далеко, но, безусловно, есть и другие приемы, которые могут ускорить процесс.
источник
Я предлагаю сделать дерево букв на основе слов. Дерево будет состоять из буквенных структур, например:
Затем вы строите дерево, с каждой глубиной добавляя новую букву. Другими словами, на первом уровне был бы алфавит; затем с каждого из этих деревьев будет еще 26 записей и так далее, пока вы не произнесете все слова. Держитесь за это проанализированное дерево, и оно сделает все возможные ответы быстрее, чтобы искать.
С этим разобранным деревом вы можете очень быстро найти решения. Вот псевдокод:
Это может быть ускорено с помощью небольшого динамического программирования. Например, в вашем примере два «А» находятся рядом с «Е» и «W», которые (с точки, с которой они их ударили) будут идентичны. У меня нет достаточно времени, чтобы действительно написать код для этого, но я думаю, что вы можете собрать идею.
Кроме того, я уверен, что вы найдете другие решения, если вы Google для "Boggle Solver".
источник
Просто ради интереса я реализовал один в bash. Это не супер быстро, но разумно.
http://dev.xkyle.com/bashboggle/
источник
Веселое. Я чуть не опубликовал тот же вопрос несколько дней назад из-за той же чёртовой игры! Я не сделал, однако, потому что просто искал в Google поисковик boggle Solver и получил все ответы, которые я мог хотеть.
источник
Я понимаю, что время этого вопроса пришло и ушло, но так как я сам работал над решателем и наткнулся на него, пока гуглял, я подумал, что должен опубликовать ссылку на свою, так как она кажется немного отличной от некоторых других.
Я решил использовать плоский массив для игровой доски и выполнять рекурсивные поиски для каждой буквы на доске, переходя от действительного соседа к действительному соседу, расширяя поиск, если текущий список букв является действительным префиксом в индексе. При прохождении понятия текущего слова используется список индексов на доске, а не буквы, составляющие слово. При проверке индекса индексы переводятся в буквы и проверка завершена.
Индекс представляет собой словарь грубой силы, который немного похож на три, но допускает Pythonic запросы индекса. Если в списке есть слова «кошка» и «кошка», вы получите это в словаре:
Таким образом, если current_word равен 'ca', вы знаете, что это действительный префикс, потому что
'ca' in d
возвращает True (поэтому продолжайте обход доски). И если current_word - это 'cat', то вы знаете, что это правильное слово, потому что оно является действительным префиксом и'cat' in d['cat']
тоже возвращает True.Если это так, то допускается некоторый читаемый код, который не кажется слишком медленным. Как и все остальные, затраты в этой системе на чтение / построение индекса. Решение платы довольно много шума.
Код находится по адресу http://gist.github.com/268079 . Он намеренно вертикальный и наивный с множеством явных проверок достоверности, потому что я хотел понять проблему, не прибегая к ней с кучей магии или неизвестности.
источник
Я написал свой решатель на C ++. Я реализовал пользовательскую древовидную структуру. Я не уверен, что это можно считать трий, но это похоже. Каждый узел имеет 26 ветвей, по 1 на каждую букву алфавита. Я пересекаю ветви доски сообщений параллельно веткам моего словаря. Если ветка отсутствует в словаре, я прекращаю поиск на доске Boggle. Я конвертирую все буквы на доске в целые. Так что «A» = 0. Поскольку это просто массивы, поиск всегда равен O (1). Каждый узел хранит, завершает ли он слово и сколько слов существует в его дочерних элементах. Дерево сокращается, так как слова найдены, чтобы уменьшить повторный поиск одних и тех же слов. Я считаю, что обрезка также O (1).
Процессор: Pentium SU2700 1,3 ГГц,
ОЗУ: 3 ГБ
Загружает словарь из 178 590 слов за <1 секунду.
Решает 100x100 Boggle (boggle.txt) за 4 секунды. ~ 44 000 слов найдено.
Решение 4x4 Boggle слишком быстро, чтобы обеспечить значимый тест. :)
Fast Boggle Solver GitHub Repo
источник
Для доски Boggle с N строками и M столбцами предположим следующее:
При этих предположениях сложность этого решения составляет O (N * M).
Я думаю, что сравнение времени работы этой одной примерной платы во многих отношениях не имеет смысла, но для полноты картины это решение завершается за <0,2 с на моем современном MacBook Pro.
Это решение найдет все возможные пути для каждого слова в корпусе.
источник
Это решение также дает направление для поиска в данной доске
Algo:
Вывод:
Код:
источник
Я реализовал решение в OCaml . Он предварительно компилирует словарь как три и использует частоты двухбуквенных последовательностей, чтобы исключить ребра, которые никогда не могут появиться в слове, чтобы ускорить обработку.
Он решает ваш пример платы за 0,35 мс (с дополнительным временем запуска 6 мс, которое в основном связано с загрузкой дерева в память).
Найденные решения:
источник
/usr/share/dict
словарь, и некоторые слова действительно отсутствуют (например, EMBOLE).Решение Node.JS JavaScript. Вычисляет все 100 уникальных слов менее чем за секунду, включая чтение файла словаря (MBA 2012).
Вывод:
["FAM", "TUX", "TUB", "FAE", "ELI", "ELM", "ELB", "TWA", "TWA", "SAW", "AMI", "SWA" , "SWA", "AME", "SEA", "SEW", "AES", "Шило", "AWE", "SEA", "АВВА", "MIX", "MIL", "АСТ",» ASE», "МАКС", "ДЕД", "MAW", "МЫ", "AWE", "МЭС", "Шило", "ЛОЖЬ", "LIM", "АВВА", "AES", "НО" , "BLO", "WAS", "ОФР", "WEA", "Лей", "LEO", " большие объекты", "LOX", "ОРЭ", "МАСЛО", "ОЛЙ", "WEA",» WAE», "ВОСК", "WAF","MILO", "ИСТ", "Wame", "ТВАС", "TWAE", "ЭМИЛЬ", "WEAM", "ОИМЭ", "AXIL", "WEST", "TWAE", "КОНЕЧНОСТЕЙ", "Wase », "WAST", "BLEO", "STUB", "испарения", "Бола", "ЛАЙМ", "ССРВ", "ЛИМА", "МЕЗ", "ныть", "ОСЬ", "FAME", "АЕС", "МИЛЯ", "AMIL", "Seax", "ШВА", "SEMI", "поплыл", "AMBO", "AMLI", "AXILE", "Amble", "СВАМИ", "AWEST », "AWEST", "Limax", "LIMES", "лимба", "подвешенном", "EMBOX", "SEMBLE", "эмболия", "переворачивать", "FAMBLE"]ВОСТОК», "Wame", "TWAS", "TWAE", "EMIL", "WEAM", "ОИМЭ", "AXIL", "WEST", "TWAE", "КОНЕЧНОСТЕЙ", "Wase", "WAST" , "BLEO", "STUB", "испарения", "Бола", "ЛАЙМ", "ССРВ", "ЛИМА", "МЕЗ", "ныть", "ОСЬ", "FAME", "АЕС",» МИЛЯ», "AMIL", "Seax", "ШВА", "SEMI", "поплыл", "AMBO", "AMLI", "AXILE", "иноходью", "SWAMI", "AWEST", "AWEST" , "Limax", "LIMES", "лимба", "подвешенном", "EMBOX", "SEMBLE", "эмболия", "переворачивать", "FAMBLE"]ВОСТОК», "Wame", "TWAS", "TWAE", "EMIL", "WEAM", "ОИМЭ", "AXIL", "WEST", "TWAE", "КОНЕЧНОСТЕЙ", "Wase", "WAST" , "BLEO", "STUB", "испарения", "Бола", "ЛАЙМ", "ССРВ", "ЛИМА", "МЕЗ", "ныть", "ОСЬ", "FAME", "АЕС",» МИЛЯ», "AMIL", "Seax", "ШВА", "SEMI", "поплыл", "AMBO", "AMLI", "AXILE", "иноходью", "SWAMI", "AWEST", "AWEST" , "Limax", "LIMES", "лимба", "подвешенном", "EMBOX", "SEMBLE", "эмболия", "переворачивать", "FAMBLE"]"TWAE", "ЭМИЛЬ", "WEAM", "ОИМЭ", "AXIL", "WEST", "TWAE", "КОНЕЧНОСТИ", "Wase", "WAST", "BLEO", "STUB", "испарения », "Бола", "ЛАЙМ", "ССРВ", "ЛИМА", "МЕЗ", "ныть", "ОСЬ", "FAME", "АЕС", "МИЛЯ", "AMIL", "Seax", "ШОВ", "SEMI", "поплыл", "AMBO", "AMLI", "AXILE", "Amble", "СВАМИ", "AWEST", "AWEST", "Limax", "LIMES", "лимба », "подвешенном", "EMBOX", "SEMBLE", "эмболия", "переворачиваться", "FAMBLE"]"TWAE", "ЭМИЛЬ", "WEAM", "ОИМЭ", "AXIL", "WEST", "TWAE", "КОНЕЧНОСТИ", "Wase", "WAST", "BLEO", "STUB", "испарения », "Бола", "ЛАЙМ", "ССРВ", "ЛИМА", "МЕЗ", "ныть", "ОСЬ", "FAME", "АЕС", "МИЛЯ", "AMIL", "Seax", "ШОВ", "SEMI", "поплыл", "AMBO", "AMLI", "AXILE", "Amble", "СВАМИ", "AWEST", "AWEST", "Limax", "LIMES", "лимба », "подвешенном", "EMBOX", "SEMBLE", "эмболия", "переворачиваться", "FAMBLE"]"WEST", "TWAE", "КОНЕЧНОСТИ", "Wase", "WAST", "BLEO", "STUB", "испарения", "Бола", "ЛАЙМ", "ССРВ", "ЛИМА", "МЕЗ », "ныть", "ОСЬ", "FAME", "АЕС", "МИЛЯ", "AMIL", "Seax", "ШВА", "SEMI", "поплыл", "AMBO", "AMLI", "AXILE", "Amble", "СВАМИ", "AWEST", "AWEST", "Limax", "LIMES", "лимба", "подвешенном", "EMBOX", "SEMBLE", "эмболия", "переворачивать », "FAMBLE"]"WEST", "TWAE", "КОНЕЧНОСТИ", "Wase", "WAST", "BLEO", "STUB", "испарения", "Бола", "ЛАЙМ", "ССРВ", "ЛИМА", "МЕЗ », "ныть", "ОСЬ", "FAME", "АЕС", "МИЛЯ", "AMIL", "Seax", "ШВА", "SEMI", "поплыл", "AMBO", "AMLI", "AXILE", "Amble", "СВАМИ", "AWEST", "AWEST", "Limax", "LIMES", "лимба", "подвешенном", "EMBOX", "SEMBLE", "эмболия", "переворачивать », "FAMBLE"]ССРВ», "ЛИМА", "MESA", "ныть", "ОСЬ", "FAME", "ASEM", "МИЛЯ", "AMIL", "Seax", "ШВА", "SEMI", "поплыл" , "AMBO", "AMLI", "AXILE", "Amble", "СВАМИ", "AWEST", "AWEST", "Limax", "LIMES", "лимба", "подвешенном", "EMBOX",» SEMBLE», "эмболия", "переворачиваться", "FAMBLE"]ССРВ», "ЛИМА", "MESA", "ныть", "ОСЬ", "FAME", "ASEM", "МИЛЯ", "AMIL", "Seax", "ШВА", "SEMI", "поплыл" , "AMBO", "AMLI", "AXILE", "Amble", "СВАМИ", "AWEST", "AWEST", "Limax", "LIMES", "лимба", "подвешенном", "EMBOX",» SEMBLE», "эмболия", "переворачиваться", "FAMBLE"]Limax», "LIMES", "лимба", "подвешенном", "EMBOX", "SEMBLE", "эмболия", "переворачивать", "FAMBLE"]Limax», "LIMES", "лимба", "подвешенном", "EMBOX", "SEMBLE", "эмболия", "переворачивать", "FAMBLE"]
Код:
источник
Поэтому я хотел добавить еще один способ решения этой проблемы, поскольку все любят PHP. Я хотел бы провести небольшой рефакторинг, например, использовать сопоставление регулярных выражений для файла словаря, но сейчас я просто загружаю весь файл словаря в wordList.
Я сделал это, используя идею связанного списка. Каждый узел имеет символьное значение, значение местоположения и следующий указатель.
Значение местоположения - то, как я узнал, связаны ли два узла.
Таким образом, используя эту сетку, я знаю, что два узла соединены, если местоположение первого узла равно расположению второго узла +/- 1 для той же строки, +/- 9, 10, 11 для строки выше и ниже.
Я использую рекурсию для основного поиска. Он берет слово из wordList, находит все возможные начальные точки, а затем рекурсивно находит следующее возможное соединение, имея в виду, что он не может перейти в местоположение, которое он уже использует (именно поэтому я добавляю $ notInLoc).
В любом случае, я знаю, что он нуждается в некотором рефакторинге, и хотел бы услышать мысли о том, как сделать его чище, но он дает правильные результаты на основе файла словаря, который я использую. В зависимости от количества гласных и комбинаций на доске, это может занять от 3 до 6 секунд. Я знаю, что, как только я preg_match словарь результатов, это значительно уменьшится.
источник
Я знаю, что я действительно опаздываю на вечеринку, но я реализовал, как упражнение по кодированию, решатель ошибок в нескольких языках программирования (C ++, Java, Go, C #, Python, Ruby, JavaScript, Julia, Lua, PHP, Perl) и Я думал, что кто-то может быть заинтересован в них, поэтому я оставляю ссылку здесь: https://github.com/AmokHuginnsson/boggle-solvers
источник
Вот решение Использование предопределенных слов в наборе инструментов NLTK. В NLTK есть пакет nltk.corpus, в котором у нас есть пакет, называемый словами, и он содержит более двух слов английского языка, которые вы можете просто использовать в своей программе.
После создания вашей матрицы преобразуйте ее в массив символов и выполните этот код
Вывод:
Я надеюсь, что вы поняли.
источник
Вот моя реализация Java: https://github.com/zouzhile/interview/blob/master/src/com/interview/algorithms/tree/BoggleSolver.java
Построение Trie заняло 0 часов, 0 минут, 1 секунда, 532 миллисекунды
Поиск слова занял 0 часов, 0 минут, 0 секунд, 92 миллисекунды
Примечание: я использовал словарь и матрицу символов в начале этой темы. Код был запущен на моем MacBookPro, ниже приведена некоторая информация о машине.
Название модели: MacBook Pro
Идентификатор модели: MacBookPro8,1
Имя процессора: Intel Core i5
Частота процессора: 2,3 ГГц
Количество процессоров: 1
Общее количество ядер: 2
Кэш- память L2 (на ядро): 256 КБ
Кэш-
память L3: 3 МБ Память: 4
Версия загрузочного ПЗУ GB : MBP81.0047.B0E
Версия SMC (система): 1.68f96
источник
Я решил это тоже с Java. Моя реализация имеет длину 269 строк и довольно проста в использовании. Сначала вам нужно создать новый экземпляр класса Boggler, а затем вызвать функцию решения с сеткой в качестве параметра. Загрузка словаря из 50 000 слов на мой компьютер занимает около 100 мс, и он находит слова примерно за 10-20 мс. Найденные слова сохраняются в ArrayList,
foundWords
.источник
Я решил это в с. На моей машине требуется около 48 мс (примерно 98% времени уходит на загрузку словаря с диска и создание файла). Словарь это / usr / share / dict / american-english, в котором 62886 слов.
Исходный код
источник
Я решил это отлично и очень быстро. Я положил его в приложение для Android. Посмотрите видео по ссылке в магазине воспроизведения, чтобы увидеть его в действии.
Word Cheats - это приложение, которое "взламывает" любую игру в стиле матрицы. Это приложение было построено, чтобы помочь мне обмануть слово скремблер. Его можно использовать для поиска слов, разрыва слов, слов, поиска слов, взлома слов, изумления и многого другого!
Это можно увидеть здесь https://play.google.com/store/apps/details?id=com.harris.wordcracker
Просмотрите приложение в действии на видео https://www.youtube.com/watch?v=DL2974WmNAI
источник