Ответы пользователя по тегу Алгоритмы
  • Найти пары слов связанных с 4ми и более одинаковыми url?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Во-первых, я бы с помощью бора все урлы перенумеровал. Теперь в задаче есть 400,000 ключевых слов, связанных с 10-ю числами.

    Далее, В каждой группе по 10 чисел есть 10!/4!/6! = 840 четверок. Всего различных четверок наберется 840*400000 ~= 330,000,000. Это не так много. Для хранения всей этой радости, правда, понадобится ~8 гигабайт памяти, но это подъемно. Потом вам надо среди этих 300 миллионов найти совпадающие. Можно отсортировать (лучше радиксом) или воспользоваться хеш таблицей (правда тут еще больше памяти потребуется).

    Это будет на много порядков быстрее сравнивания каждого слова с каждым или перебор 4-х урлов.
    Все за несколько секунд должно отработать.
    Ответ написан
    1 комментарий
  • Сортировка расческой. Что такое число 1.247?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Судя по всему, это число вылезло в результате эксперементов каких-то исследователей. Они просто попробовали кучу разных факторов и нашли что при 1.247 вроде как быстрее в среднем. Формулу по это число потом какой-то шутник придумал. Кроме как в русской википедии (без ссылки на источник) я нигде эту формулу найти не могу.

    Влияет оно так: если число слишком большое, то мелкие элементы в конце массива не успевают перехать в начало на итерациях с достаточно большим шагом; если же число слишком мелкое, то делается много лишних итераций.
    Ответ написан
    Комментировать
  • Какой самый быстрый алгоритм поиска в массиве непересекающихся отрезков, поиск отрезка внутри которого лежит точка?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Если нет простой формулы, как в линейном случае (например, логарифм или корень числа), то за О(1) можно только если числа не очень большие: надо предподсчитать ответы для всех возможных индексов.

    Если запросов много (больше чем отрезков) и они уже сортированные, то можно обработать их все сразу пачкой, пройдясь один раз по массиву отрезков. Это будет быстрее чем за логарифм обрабатывать каждый запрос отдельно. Но это очень частный случай. Сортировать запросы будет медленнее бинпоиска, если они уже не даны по порядку.

    Если запрос только один, то можно не париться, ибо время на загрузку массива с отрезками вы уже потратили и вся программа уже точно O(n) как минимум.
    Ответ написан
    Комментировать
  • Как устроены хэштаблицы?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Сначала выделяется массив какого-то размера, например 256. Обычно длина - степень двойки. Потом хеш обрезается до размера таблицы. Если элементов становится слишком много, то происходит перехеширование - размер таблицы увеличивается, и все элементы в нее перезапихиваются.

    Но да, если в таблицу запихать много элементов, а потом почти все оттуда удалить, то она будет большая и почти вся пустая.

    Edit:

    Эта "проблема" никак не решается. Это и не проблема вовсе. Просто хеш-таблицы работают быстрее всяких балансированных деревьев или тупо сортированного массива за счет большего расхода памяти. Это нужно знать и дальше уже решать - что вам больше подходит под вашу конкретную задачу.
    Ответ написан
    Комментировать
  • Алгоритм разбиения?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Алгоритм простой - рекурсивно генерируйте все разбиения.
    Текущий предмет может пойти или в одну из занятых кучек, или в первую пустую, если они есть.
    Так, первый предмет обязательно пойдет в первую группу. Второй может пойти в ту же или во вторую. И т.д.
    Чтобы не было пустых групп, элемент обязательно кладется в первую пустую, если их осталось столько же, сколько осталось элементов распределить. Ну, и, нельзя создавать новую группу, их уже, сколько надо. Удобнее распологать элементы с конца.
    Что-то вроде такого:
    def partition(n, k, answer):
        if n == 0 :
          yield answer
        cur_len = len(answer)
        if k-cur_len < n:
            for i in range(cur_len):
                answer[i].append(n)
                yield from partition(n-1, k, answer)
                answer[i].pop()
        if cur_len < k:
            answer.append([n])
            yield from partition(n-1,k, answer)
            answer.pop()
    
    for x in partition(4, 2, []):
        print(x)


    Вроде как set_partitions из пакета more-itertools делает именно то, что вам надо, но так-то алгоритм - всего несколько строк.

    Этот алгоритм переберет все разбиения без повторов, потому что групировка элементов однозначно задает и порядок групп (группа с 1 - всегда первая. Потом группа с минимальным элементом - вторая и т.д.)

    Edit:
    Если же вам надо разбить предметы по 1, 2 и т.д. групп сразу же, а не только на фиксированные k групп, то надо чуть поменять условия в коде - надо сделать return в начале, после yield, и можно будет ставить предмет в любую группу или в новую всегда. Параметр k будет не нужен.
    Ответ написан
  • Какая сложность под капотом у сравнения строка?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    O(1), если "var/www/project" фиксированна. Сравнение двух произвольных строк - линейная сложность.
    Ответ написан
    Комментировать
  • Какая сложность данного алгоритма?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Сложность: простой.

    Если вам нужна ассимптотическая временная сложность - то O(n).
    Эта сложность меряется в зависимости от размера входных данных. Какие у вас входные данные-то? Строка slug, url.

    Эти данные конкатенируются (O(n)) и передаются библиотеке. До 10 раз. Библиотека их парсит, делает dns запрос, открывает сетевое подключение к web серверу, получает данные, парсит ответ. Там тоже есть линейная, видимо, зависимость от длины строки. Ее надо распарсить, записать в сетевой сокет и так далее. Вот получение данных по уже установленному http соединению от длины строки не зависит, поэтому в сложности алгоритма не учавствует.
    Ответ написан
    1 комментарий
  • Как написать код, где надо узнать в каком диапазоне число(без if else)?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    По-скольку тут все диапазоны одинаковой длины, то можно формулой:

    n = (x - 30)/10;

    Тут есть проблема, что интервалы идут и после 6 и еще и в отрицательную сторону.

    Можно навесить на это сверху min/max так:

    min(6, max(1, n));

    Min и max реализуются без if - это известная задача, гуглите.

    Edit: Сначала не опнял вопрос, думал надо по заданию без if написать это.

    Все-равно, самый быстрый и простой код будет с формулой выше. Только можно проверить на принадлежность крайним интервалом через if:

    if (x <= 49) return 1;
    if (x >= 90) return 6;
    return (x-50)/10 + 2;
    Ответ написан
    Комментировать
  • Более быстрый способ нахождения всех делителей числа?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Это самый быстрый способ факторизации одного числа. Если не хватает, то может в задаче можно факторизовать все числа сразу. Каким нибудь решетом можно найти минимальный делитель для всех чисел до n за O(n). Дальше каждое число раскладывается на множители моментально.
    Ответ написан
  • Как вписать прямоугольник в многоугольник?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Если результат не должен быть горизонтально-вертикальным по условию, то в оптимальный прямоугольник может быть и наклонен (смотрите замечательный контр-пример от dollar).

    В этом случае, ваша задача это весьма сложная геометрическая задача.
    Я знаю один способ решить ее - перебрать все максимальные прямоугольники (те, что нельзя увеличить просто сдвинув).
    Такие прямоугольники будут касаться заданного многоугольника углами и/или сторонами. Надо будет перебрать все случаи - что чего там касается, построить прямоугольник и проверить, что он лежит внутри заданного многоугольника (пересечь все стороны многоугольника со сторонами квадрата и убедиться, что пересечений нигде нет и также, что центр прямоугольника лежит внутри многоугольника), и из всех таких выбрать самый большой.

    Но тут слишком много случаев. Это очень сложная задача строк этак на 1000 мозгодробящей геометрии.
    Ответ написан
    Комментировать
  • Где используется бинарный поиск?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Да много где.

    Вот, в хроме, например.

    Из примеров там видно - поиск в списке заблокированных usb устройств, поиск графем в выводимом тексте, что-то с сертификатами, с метриками, при выборе какие видео фреймы рисовать...

    Бинарный поиск - слишком фундаментальный алгоритм и применяется везде, где надо на остортированном массиве данных что-то найти. В любом не тривиальном проекте, где кроме формочек и кнопочек есть хоть какие-то данные, эта ситуация может встретится и не раз.
    Ответ написан
    Комментировать
  • Как реализовать завершение игры "Жизнь" на Си?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Раз поле конечное, то цикл будет обязательно, но алгоритмически понять, что вот мы уже на нем - никак нельзя.

    Можно запоминать предыдущие поля. Хотя бы в виде хешей для экономия памяти. Чтобы из-за коллизии не заврешаться раньше времени, можно считать несколько принципиально разных хешей (допустим, sha256 и какой-то полиномиальный хеш), и плюс брать "слепок" от поля (какие-то 256 разбросанных по полю клеток).

    Или, если поле не большое, то можно вместе с хешом хранить все поле. Если где-то хеши совпали, то дальше нужнол сравнивать уже поля целиком поклеточно.
    Ответ написан
    1 комментарий
  • Как рассчитать оптимальную погрузку груза в автомобиль?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Это называется "задача упаковки" (packing problem). В простейшем случае - прямоугольников в прямоугольник. Нашласть статья на хабре и какая-то научная статья. Дальше вам придется гуглить самостоятельно.

    Вообще, это NP-полная задача, поэтому для решения скорее всего придется использоваать метод ветвей и границ или какие-то переборы с отсечениями. Если коробки занимают почти все место в машине и решение есть, но оно редкое, то найти его за разумное время вы сможете, скорее всего, лишь для относительно небольшого количества коробок (штук 40-50).

    А разрешение класть на бок вообще усложняет задачу кардинально. Это вам придется еще для каждой коробки перебирать, а каким боком ее класть на пол.

    А если их еще друг на друга класть можно, то перебор еще сложнее становится и вы решить задачу сможете уже лишь для 10-20 коробок. Иначе вам понадобится супер компьютер и нелеля вычислений.

    Но, если коробки легко помещаются в машину и их туда вообще почти как угодно кидать можно, то решение перебором найдется быстро, особенно если сделать алгоритм рандомизированным.
    Ответ написан
    Комментировать
  • Как найти длинный путь между двумя точками?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Зачем вам самый длинный путь? Вообще, эта задача очень сложная. Кратчайший путь можно найти обходом в щирину или глубину, быстро и просто. Самый длинный - только полным перебором. Возможно, его можно как-то соптимизировать используя особенности вашей конкретной задачи (вроде заполнения прямоугольника змейкой и конструтирование маршрута из таких шаблонов), но это тоже очень сложно.
    Ответ написан
    4 комментария
  • Как работает этот рекурсивный алгоритм разложения на слагаемые?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Функция генерирует все разбиения числа n на слагаемые не больше maxx. Ддя этого ыункуия перебирает, а какое же максимальное число будет в разбиении (цикл по i), берет это число и рекурсивно разбивает оставшуюся часть. Обратите внимание, в качестве maxx в рекурсии передается i. Ведь именно это было максимальное число в перебираемом разбиении. Значит следующее не может его превышать.

    Вся эта сложность с максимальным числом сделана, что бы не перебирать перестановки слагаемых. Ведь 4=1+2+1 можно по идее получить тремя способами, меняя порядок. Генерируя слагаемые в не возрастающем прядке, мы избавляемся от таких дубликатов.
    Ответ написан
    Комментировать
  • Какой можно применить алгоритм для хранение индекса для 50 миллиардов записей в golang?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    vgray, Удаляются ли записи?

    Так-то, поиск на полное совпадение по строке не самое сложное. Какое-нибудь B-Tree или Trie - отлично подойдут тут. Проблема только в том, что оно в память не влезает, поэтому придется повозиться с хранением этого всего кусками в файлах. B-Tree как раз для этого и сделано, но оно будет медленнее работать со строками. Аккуратно порезанный на куски Trie будет быстрее.
    Ответ написан
    Комментировать
  • Как найти площадь квадрата, имея 2 отрезка?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Отлично, в комментариях уточнили задачу - надо описать вокруг двух заданных прямоугольников квадрат минимальной площади. Прямоугольники не пересекаются и не касаются и параллельны осям координат.

    Не совсем пока еще понятно, квадрат может быть ориентирован как угодно, или тоже должен быть параллелен осям координат? Судя по тупости формулеровок я думаю, что составители задачи имели в виду более простой вариант, и стороны квадрата тоже должны быть параллельны.

    В этом случае можно сначала построить обрамляющий прямоугольник вокруг обоих прямоугольников (взять максимум и минимум по каждой оси из всех углов). А потом взять его большую сторону в качестве стороны квадрата-ответа (возвести в квадрат и вывести).

    Если же это не сработает и квадрат можно вращать, то тут все сложно. Путем очень хитрых геометрических рассуждений можно доказать, что квадрат в оптимальном случае, все-таки, будет параллелен осям координат и просто написать решение выше. Ну, или, если не верите, то можно ввести угол поворота как переменную, написать функцию, котороя поворачивает все точки на данный угол, а потом ищет (по алгоритму в начале) площадь описанного параллельного осям квадрата, и потом запустить тернарный поиск минимума по этой функции.
    Ответ написан
    2 комментария
  • Как однозначно конвертировать цвет из RGB в HSL и обратно, получая один и тот же результат?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Вообще, преобразования можно сделать обратимыми. Математические формулы однозначны.

    Похоже там тупо где-то стоит округление вниз, ведь разница после преобразований по всем каналам - ровно 1. Может, это значение RGB в HSL на самом деле что-то вроде (15.01, 30.5, 49.9). Но в пиксели HSL в итоге запишутся целые числа (0-255). Из-за этого округления при обратном преобразовании получается не 0x91 а 0x90.6, что, опять же, округляется вниз.

    Если так важна полная обратимость преобразований, попробуйте использовать 10-битные или 16-битные форматы пикселей (расширяя исходный 8-битный RGB нулями справа). Тогда эти округления не испортят важные вам 8 старших бит.
    Ответ написан
    1 комментарий
  • Как найти похожие отрезки в 2 множествах данных, или корреляцию с смещением?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Формализуйте метрику корелляции. Там если расписать - то в итоге все придет к свертке (если одну последовательность развернуть сначала). Ее можно за n log n подсчитать быстрым преобразованием фурье.
    Ответ написан
    Комментировать
  • Kак показать на экране все числа до заданного числа, которые будут кратны второму заданному числу через цикл (while)?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Ну, пишем цикл, который будет выводить числа. В самом тупом случае - цикл перебирает все числа и проверяет их на делимость и если надо выводит. Более умный подход - начать с 0 и прибавлять число-делитель на каждой итерации после вывода, чтобы сразу пропускать все неделящиеся числа.

    Это реально 3 строки кода, если вам непонятно, снова почитайте учебник про циклы.
    Ответ написан
    Комментировать