Задать вопрос
Ответы пользователя по тегу Алгоритмы
  • Как устроены хэштаблицы?

    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 строки кода, если вам непонятно, снова почитайте учебник про циклы.
    Ответ написан
    Комментировать
  • Как перевести строку в число в ассемблере?

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

    Надо уметь только делить с остатком и умножать на 10. Как перевести 1234 в строку? Можно взять последнюю цифру - осток от деления на 10. Вот вы получили цифру 4. В строке это будет символ "4", или байт со значением 0x34. Вообще, для получения символа по цифре - надо прибавить 0x30. Это мы взяли остаток, а вот результат деления - 123. Можно продолжить перевод так же и мы получим символы в обратном порядке.

    Итак, пока число не 0, делим нацело на 10. Остаток приписываем в ответ переводя в символ. В конце разворачиваем строку.

    Перевод же из строки в число делается проще - идем циклом по строке, умножаем переменную на 10 и прибавляем тукущую цифру.
    Ответ написан
    Комментировать
  • Как эффективней рассчитать время работы с учетом выходных и праздников?

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

    Ну а потом для каждой задачи можно понять сколько там было праздников в ее интервале просто вычтя две частичные суммы из массива.

    Второй вариант - выходные дни недели подсчитать ручками: если дата начала и дата коца в одной неделе, то выходных нет. Иначе, если начало не понедельник - то сдвинуть ее до следующего понедельника и прибавить следующие субботу и воскресение к счетчику. Потом, если дата конца не пятница - сдвинуть ее на предудущий понедельник. Теперь разность между датами кратна 7 и покрывает сколько-то недель целиком. Делите разность на 7 и умножайте на 2, чтобы подсчитать, сколько там суббот и воскресений (разность может быть и 0 и это нормально).

    Потом надо ручками же подсчитать все праздники. Для этого составьте в массиве даты всех календарных праздников в затронутых годах отсортированные. Потом для каждой задачи в этом массиве бинпоиском найдите первый и последний праздник в отрезке. Вот вы уже знаете их количество (разность индексов +1). Так же можно еще вести список всех рабочих суббот и воскресений. Этот список дат можно, наверно, где-то из интернета автоматически скачивать, а можно и тупо ручками в январе вбивать в базу.
    Ответ написан
    Комментировать
  • Почему один код выполняется быстрее другого C++?

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

    Первый вариант отбрасывает дробные части от копеек, а второй отбрасывает дробные части от рублей. Ведь при делении на 100 в целых числах идет округление вниз. Если брать p процентов с округлением вниз от числа в рублях, то и получится целое число в рублях. Если брать от числа в копейках, то и получится целое число в копейках.

    Поскольку второй код отбрасывает все копейки при прибавлении, то ему требуется больше итераций, чтобы дойти до y. На самом деле он может даже виснуть, если там получается прибавление 0.
    Ответ написан
    1 комментарий