Ответы пользователя по тегу Алгоритмы
  • Рандомное число и вероятность выпадения?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Взять случайное (дробное) число от 0 до 100, включая 0, исключая 100.

    Порог – значение, выше которого будем считать выигрышем, ниже проигрышем игрока.
    Процент больше 0 – чистый рандом. Порог = 50.
    Процент –100 — без шансов. Порог = 100.
    Между процентом 0 и –100, порог линейно меняется от 50 до 100.
    Ответ написан
    2 комментария
  • Как решить этот корнеркейс в реализации алгоритма поиска мажоритарного элемента через разделяй-и-властвуй?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    512766168
    717383758
    5
    126144732
    5
    ---------------
    573799007
    5
    5
    5
    405079772
    в первой половинке "5" не будет мажоритарным элементом:
    пятёрок всего 2, тогда как надо > N/2, т.е. от 2.5 (3)
    Ответ написан
    Комментировать
  • Как осуществить поэлементное сравнение множества массивов друг с другом и создание нового массива из лучших пар, троек, четверок и т.д.?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Если я правильно понял, есть двумерная таблица единиц и нулей, например
    0 1 0 0 1 1 1 0
    0 0 1 0 1 1 1 0
    1 1 1 0 0 1 1 0
    1 1 0 0 1 1 1 0

    и хочется получить максимальные «островки» единиц.
    Не обязательно сплошных. Такие наборы строк и столбцов, где все единицы.
    Вроде бы это задача поиска максимальной биклики в двудольном графе.

    В примере это будет, наверное, строки [0, 1, 3] и столбцы [1, 5, 6] весом, соотв., 3 x 3 = 9
    Ответ написан
    Комментировать
  • Как управлять памятью в javascript?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Объект числа занимает больше памяти, чем само число. Где-то пишут, что байты числа (8) + ещё 8 байт. Поэтому в 2 раза больше памяти потребуется только на числа: 4e9 * 16 байт = 64e9 байт примерно 60 Гб.
    Эффективнее использовать память можно было бы с помощью ArrayBuffer.
    Ответ написан
    3 комментария
  • Как задать и менять позицию элементов в таблице?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Чисто алгоритмически-теоретически, можно организовать связный список.

    Например, двусвязный. У каждой строки ещё 2 поля: следующий_id, предыдущий_id

    Когда позиция элемента меняется, это два действия:
    1. выемка элемента: обновляются два его соседа, чтобы связаться напрямую.
      пример
      id   next prev
      1    2    null
      2    3    1     <-- этого забираем
      3    4    2
      
      --------------
      1    3    null
      3    4    1

    2. вставка: рвётся связь двух и заменяются их указатели на вставленный, и у вставленного тоже.
      пример
      id   next prev
      7    8    6     <-- вставить после этого
      8    9    7
      
      
      --------------
      7    2    6
      2    8    7 
      8    9    2
    При переносе элемента понадобится обновить не более 2 + 2 + 1 = 5 строк.

    Получать такой список в нужном порядке средствами MySQL - нетривиально. Но можно просто вынимать весь целиком, а рисовать-сортировать в правильном порядке уже на клиенте.
    Ответ написан
  • Как проверить чётность четверичного числа?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Делится ли младшая цифра на 2 — последняя цифра 0 или 2, значит, чётное.
    Ответ написан
  • Как заполнить большую матрицу числами?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Проще: npm install ml-matrix документация

    import { Matrix } from 'ml-matrix';
    
    const matrix = new Matrix(12, 31);
    Ответ написан
    Комментировать
  • Существует ли структура данных «расширяемая 2D-таблица»?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    можно не ограничиваться 2D
    Как вариант — подсмотреть реализацию ndarray в Numpy.
    Частично описано здесь (на англ.)
    Данные хранятся в буфере – типа массива в C. И есть метаданные, описывающие "вид" на этот буфер.
    Когда меняется форма, создаётся новый объект метаданных, без изменений в самих данных.
    Но тут не раскрывается тема вставки, как это изменяет размер буфера – создают новый или расширяют старый. В конце или распихивают по строкам.
    Ответ написан
    Комментировать
  • Как организовать выборку эффективных вариантов из таблицы?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Похоже на задачу об упаковке, которая решается полным перебором всех вариантов.
    Тут два типа условий: строгие – по параметрам 1 и 3; и нестрогий поиск минимума по стоимости.

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

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Чтобы соблюсти условие строго-больше, можно записать все слагаемые через их ненулевые разницы.
    x > y, значит, x = y + ненулевое_число. Можно так перезаписать слагаемые:
    m          = k0 
    z = m + k1 = k0 + k1
    y = z + k2 = k0 + k1 + k2
    x = y + k3 = k0 + k1 + k2 + k3
    -----------------------------
    m+z+y+x    = 4k0 + 3k1 + 2k2 + k3 = SUM
    ki — это натуральные числа от 1.
    Получили все k — вычислили x, y, z, m.

    Сначала получим k0
    Т.к. на k1..k3 уходит минимум 6, когда все по 1,
    для k0 остаётся диапазон [1, (SUM - 6) / 4]
    при этом k0 должен быть целым.

    Выбрав случайный k0 в этом диапазоне,
    получаем новую целевую сумму SUM1 = SUM - 4 * k0,
    которую нужно заполнить 3k1 + 2k2 + k3 = SUM1

    Рекурсия. Но на последнем шаге k3 это весь остаток.

    const addUpTo = (top, n) => {
      const getDiffs = (sum, n, acc = []) => {
        if (n === 1) {
          x = sum;
        } else {
          const headroom = (n - 1) * n / 2;
          const cap = Math.floor((sum - headroom) / n);
          if (cap < 1) throw("Impossible. " + JSON.stringify(acc));
          x = 1 + Math.floor(Math.random() * cap);
        }
    
        acc.push(x);
    
        if (n <= 1) {
          return acc;
        } else {
          return getDiffs(sum - x * n, n - 1, acc);
        }
      }
    
      return getDiffs(top, n).map((_, i, a) => a.reduce((acc, c, j) => j <= i ? acc + c : acc)).reverse();
    }
    
    addUpTo(100, 4)  /*
    [ 34, 30, 21, 15 ]
    [ 31, 24, 23, 22 ]
    [ 66, 17, 13, 4 ]
    [ 47, 22, 21, 10 ]
    ...
    */
    
    addUpTo(10, 4)  // [ 4, 3, 2, 1 ]
    addUpTo(9, 4)   // ошибка, невозможно разложить
    Ответ написан
    Комментировать
  • Как узнать приблизительную сложность алгоритма, зная время его выполнения?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Абстрагируясь от алгоритмов и их сложности в Big-O-нотации, задача сводится к подсчёту различий значений данной функции и функций-кандидатов на каком-то множестве контрольных точек.

    Взять какой-то набор значений [x0, x1, ... xN].
    Получить «правильные» y_true = [f(x0), f(x1), ... f(xN)]
    Для каждой функции-кандидата из этих же x получить их «предсказания» y_pred = [Fn(x0), Fn(x1), ... Fn(xN)]

    Определить, какая из функций меньше всего «ошиблась». Для этого сложить квадраты разниц y_true - y_pred выданных каждой из функций на наборе входных значений x

    Наименьшая сумма укажет наиболее вероятного кандидата.

    Например,
    x = [1, 2, 4, 8, 16, 32, 64]
    f(x) = [y0, y1, y2, y3, y4, y5, y6]
    
    // n
    [1, 2, 4, 8, 16, 32, 64]
    sum = (y0 - 1)^2 + (y1 - 2)^2 + (y2 - 4)^2 + ... + (y6 - 64)^2 = sum0
    
    // n^2
    [1, 4, 16, 64, 256, 1024, 4096]
    sum =  (y0 - 1)^2 + (y1 - 4)^2 + (y2 - 16)^2 + ... + (y6 - 4096)^2 = sum1
    
    // так же посчитать суммы ошибок для остальных функций:
    // n * log(n),  n!


    минимальное значение среди sumN укажет функцию, наиболее близкую к искомой.
    Ответ написан
  • Как лучше организовать структуру данного кода?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Если действия симметричны, т.е. при X > (C > B > A) действия те же, что при X > (A > B > C),
    можно привести переменные к однозначно возрастающему варианту — поменять местами A и C если A > C.
    Так вариантов останется 7.
    if (A > C) [A, C] = [C, A]; // поменять местами значения A и C
                                // теперь точно A < B < C
    if (X < A) {          // вар. 0
    } else if (X == A) {  // вар. 1 
    } else if (X < B) {   // вар. 2
    } else if (X == B) {  // вар. 3
    } else if (X < C) {   // вар. 4
    } else if (X == C) {  // вар. 5
    } else { // X > C     // вар. 6
    }


    Ещё один способ — с бинарным деревом, который интуитивно но неправильно пытался подсказать xmoonlight
    Всего есть 2 * 7 = 14 вариантов. Гипотеза о том, что действия зеркальны для двух вариантов A > B > C и A < B < C вроде бы подтвердилась, поэтому оставлю первый шаг, где меняем местами A и C, чтобы последовательность точно была возрастающей.

    Остаётся 7 вариантов. Достаточно 3 битов, чтобы закодировать любой из них. Каждый бит это ответ на 1 вопрос, проверка одного условия. Т.е. достаточно всего трёх if'ов для определения нужного блока кода:
    0  1  2  3  4  5  6 
    ---o-----o-----o---   
       A     B     C      
    
    0  1  0  1  0  1  0  1
    0  0  1  1  0  0  1  1
    0  0  0  0  1  1  1  1


    Примерно так:
    if (A > C) [A, C] = [C, A]; // поменять местами значения A и C
                                // теперь точно A < B < C
    if (X > B) {
      if (X > C) {    // вар. 6
      } else {
        if (X == C) { // вар. 5
        } else {      // вар. 4
        }
      }
    } else {
      if (X > A) {
        if (X == B) { // вар. 3
        } else {      // вар. 2
        }
      } else {
        if (X == A) { // вар. 1
        } else {      // вар. 0
        }
      }
    }
    Так менее наглядно и читаемо, но сэкономили на спичках – меньше проверок.
    Не более 3 проверок условий, чтобы определиться, куда попали.
    Ответ написан
    2 комментария
  • Как решить такую задачу на логику?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Один пускай стоит, а второй туда-сюда с возрастающей амплитудой

    spoiler
    Похожая задача на англ.: Two robot with parachute in a line
    Ответ написан
    Комментировать
  • Как перебрать все элементы множества в псевдо-произвольном порядке?

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

    Вот пример кода:
    const src = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; // массив элементов
    const key = [2, 1, 0]; // номера битов для перемешивания адреса
    
    const mapIndex = (n, key) => key.reduce((p,c,i) => p | ((1 << c & n) >> c) << i, 0);
    const biject = (arr, key) => arr.map((e,i) => arr[mapIndex(i, key)]);
    
    console.log( JSON.stringify(biject(src, key)));
    // ["a","e","c","g","b","f","d","h"] 
    
    console.log( JSON.stringify(biject(src, [1,2,0])));
    // ["a","e","b","f","c","g","d","h"]


    Disclaimer. Этот способ не исчерпывает все возможные перестановки, ограничиваясь их небольшой частью. Первый и последний всегда остаются на своих местах (все "0" как ни перемешивай..)

    Upd. отличный способ подсказали на SO. Когда длина массива N, нужно взять любое простое число больше N. Оно гарантированно будет взаимнопростым с любым из чисел меньше.
    Новый адрес элемента получается из старого: адрес умножить на простое и взять остаток от деления на длину.
    {
    const src = 'abcdefgh'.split('');
    const N = src.length; // 8
    const Prime = 37;  // Prime > N
    const mapIndex = (i, N, Prime) => (i * Prime) % N;
    //for(let i  = 0; i< 8; i++) console.log(i, mapIndex(i, N, Prime))
    const shuffle = (str, Prime) => str.split('').map((e,i,a) => a[mapIndex(i, a.length, Prime)]).join('');
    
    console.log( shuffle('abcdefgh', 17));
    console.log( shuffle('abcdefgh', 19));
    console.log( shuffle('abcdefgh', 23));
    console.log( shuffle('abcdefgh', 29));
    
    abcdefgh  // не перемешалось
    adgbehcf
    ahgfedcb
    afchebgd

    Для некоторых простых чисел почему-то не происходит перемешивания: для 17, 37 при длине массива 8.
    Ответ написан
  • Какой алгоритм составить для подбора количества банок?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    это называется «задача об упаковке» (packing problem) и решается полным перебором всех вариантов.

    «Желательно» – это доп. условие, задающее «вес» разным вариантам.
    Надо сформулировать функцию потерь: на входе комбинация банок, на выходе «штраф» за неё, который складывается из объёма перебора (недобор не должен вообще приходить), и, может, из количества мелких банок (чтобы минимизировать его).
    Перебирая все варианты, считать штрафы, оставлять варианты с минимальными штрафами.

    Несколько интересных алгоритмов. См. там ещё ссылки слева.
    Ответ написан
    5 комментариев
  • Как получить цвет всех пикселей картинки без перебора пикселей в двух циклах?

    sergiks
    @sergiks Куратор тега PHP
    ♬♬
    Если картинка в несжатом формате, например, BMP, наверное, можно прямо с диска читать массив пикселей, разобравшись с форматом файла.

    Для сжатых форматов понадобится сначала распаковать изображение. Например, для PNG и библиотеки GD функцией imagecreatefrompng()
    GD не документирует прямой доступ к области памяти, где хранятся пиксельные данные полученного ресурса imageresource. Поэтому с ней единственный вариант перебирать в цикле.

    Посмотрите, что умеет ImageMagick. Например getImageColors()
    Ответ написан
    1 комментарий
  • Можно ли из заданных цифр составить последовательность чисел, являющуюся арифметической прогрессией?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Можно всегда

    В любом случае, при любых цифрах, числом более одной, можно составить «последовательность» всего из двух чисел и объявить её арифметической % )

    51791
    5,  5 + 1786 = 1791, третьим было бы 3577


    Если серьёзно, разбейте на подзадачи.

    Вот, дан набор чисел. Как быстро понять, является ли он арифм. последовательностью?
    Наверное, это должен быть набор из 3 и более чисел. Отсортировать по возрастанию, получить разницу между 0-м и 1-м. Двигаться далее, сравнить 2й и 1й. Как только разница отличится от первой, это fail. Если успешно дошли до конца массива и везде разница одна и та же — это успех, это арфим. последовательноть.

    Другая подзадача: из набора цифр составить все возможные числа. Чисел должно получиться 3 и более. Во всех вариантах перестановок, но с учетом повторяющихся цифр в исходном наборе.

    Можно добавить всяких оптимизаций. Например, проверять чётность.
    В арифметической последовательности чётность либо постоянная, либо чередуется через раз. Чётное число оканчивается на чётную цифру. Поэтому если в исходном наборе есть всего одна нечетная цифра, либо её место не в конце числа, либо в последовательности всего три числа и эта цифра в конце среднего.
    Ответ написан
  • Как можно воксельную модель разбить на очень малое количество параллелепипедов?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Похоже на задачу об упаковке: надо заполнить контейнер в форме гриба минимальным количеством «коробок» любого размера.

    Такая задача в общем случае считается NP-полной и требует перебора всех вариантов.

    Например, с этим грибом можно было бы начать с поиска самых длинных сплошных цепочек и обнаружить центральный «столб». Сделать его 1 куском.
    Но тогда самый верх и самый низ потребуют ещё 4 деталей, каждая по 2. А можно было бы столб сделать не максимально высоким, лишив 1 шага сверху и снизу. И тогда на верх и низ деталей потребовалось бы не по 4, а по 3.
    Ответ написан
    Комментировать
  • Как найти все локальные минимумы в матрице?

    sergiks
    @sergiks Куратор тега Алгоритмы
    ♬♬
    Проверять каждый элемент, сравнивая с 8 или 5 (у стенки) или 3 (в углу) соседями.
    Ответ написан