• Как мне продолжить сокращать формулу?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Два наблюдения:
    1) изначальная формула имеет вид (a=>b)*(b=>a).
    2) b = !a

    Отсюда в одно действие видно, что она вырождается в ложь: (a=>!a)*(!a=>a)

    Для второго наблюдения надо применить какой-то там закон, что !x+xy=!x+y
    Ответ написан
    4 комментария
  • Как решить проблему с типизацией getValue?

    WblCHA
    @WblCHA
    https://www.typescriptlang.org/play?#code/C4TwDgpg...

    type ExtractValuesFromSubKeys<T extends object, SK extends string, K extends keyof T & string = keyof T & string> = K extends `${string}${SK}${string}` ? T[K] : never
    
    function getValue<T extends object>(obj: T, isIncludeKey?: false): <K extends keyof T>(key: K) => T[K]
    function getValue<T extends object>(obj: T, isIncludeKey: true): <SK extends string>(subKey: SK) => ExtractValuesFromSubKeys<T, SK>[]
    function getValue<T extends object>(obj: T, isIncludeKey?: boolean) {
      return (keyOrSubKey: string) => {
        if (!isIncludeKey) {
          const key = keyOrSubKey as keyof T
    
          return obj[key];
        }
    
        const subKey = keyOrSubKey
    
        return Object.keys(obj).filter(key => key.includes(subKey)).map(key => obj[key as keyof T])
      }
    }
    
    const getter = getValue({ aaa: 1, bbb: '2', ccc: [3], abc: null }, true);
    
    const ttt1 = getter("a") // (number | null)[]
    const ttt2 = getter("bb") // string[]
    const ttt3 = getter("ccc") // number[][]
    const ttt4 = getter("unknown") // never[]
    Ответ написан
    4 комментария
  • Почему переменная класса становится undefined при обращении из метода?

    Mike_Ro
    @Mike_Ro Куратор тега JavaScript
    Python, JS, WordPress, SEO, Bots, Adversting
    Стрелочная функция не имеет своего this, соответственно возьмет его из скоупа выше:
    MyFunc = (e) => {
      console.log("MyVariable: " + this.MyVariable); // oh yes
    }
    Ответ написан
    Комментировать
  • Как из первых N натуральных чисел составить максимальное количество пар, суммы которых являются простыми?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    В вашем решении есть ошибки: Вы считаете сумму двух чисел от 0 до N, а не от 1 до N.

    А главная проблема вашего решения в том, что оно "жадное". Вы жадно берете первую папавшуюся пару, как будто так будет оптимально. Но это не так. Например, если у вас остались гири весами 2, 3, 4, 5, то брать пару 2+3 = 5 нельзя, ведь тогда оставшиеся 4+5=9 дадут не простое число.

    Это действительно можно решать через задачу о паросочетании как сказал Alexandroppolus. Вот только все алгоритмы работают за O(N^3), так что для N=500000 это решение будет работь очень долго.

    Но в вашем случае граф очень специфичный, так что надо придумать какой-то шаблон. Например, можно взять максимальное простое число P <= N+1 и набирать его всеми возможными парами (1+(P-1), 2+(P-2)). В итоге у вас остнется одна нечетная гиря (P+1)/2 и все гири >=P. Например, если N+1 простое - то это оптимальный способ.

    Я бы посоветовал написать решение через максимальное паросочетание и прогнать его для всех N <=200. Получите оптимальные ответы, посмотрите на них. Поищите какой-то паттерн в количестве пар, потом попробуйте придумать способ такое количество набрать.

    И еще немного покритикую ваш код.
    f==true. Зачем? Можно написать if(f). А вообще вам тут f не нужно, пишите if(Check(i+j)).

    Вместо
    if(a[j]!=0&&a[i]!=0&&i!=j) { 
      ...
    }

    стоит использовать "ранний выход":
    if(!a[i] || !a[j] || i == j) continue; 
    ...


    Так вложенность и сложность кода меньше. Его проще читать и понимать.

    Вместо прверки, что i != j, можно внутренний цикл гнать от n до i+1. Вам же не надо перебирать отдельно пары 1+10 и 10+1? Всегда считайте, что первое число меньше второго в паре.

    Ну, и отступы, ради всего святого, расставьте аккуратно. Любой редактор кода умеет их делать автоматически.

    Edit:
    Совместо с Alexandroppolus в комментариях придумали следующее решение: Берете минимальное простое число, большее N. Обзовем его P. Тогда берем пары N+(P-N), (N-1)+(P-N+1)... и т.д. В этих парах одно число четное, другое нечетное. И всего они покроют отрезок четной длины без дырок. Потом задача сводится к такой же, только уже с максимальным числом не N, а P-N-1.
    Эта жадность работает, потому что она всегда соберет максимально теоретически возможное количетсво пар. Может только одна 1 в конце останется.
    Ответ написан
    6 комментариев
  • Как найти последовательность букв через графы?

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

    Тогда постройте граф на n*m*l вершин. Каждая вершина соответствует тройке (x, y, k) и означает, что мы как-то походили по полю и оказались в координате (x, y), при этом набрав первые k символов искомой строки. Переходы в графе тут такие: от каждой вершины можно пойти в 4 соседние по координатам, а количество символов увеличивается на 1, если в следующей вершине читается следующая буква строки. Т.е. переходы вида (x, y, k) -> (x+1, y, k + (s[k] == grid[x+1][y] ? 1 : 0)); (x, y, k) -> (x, y+1, k + (s[k] == grid[x][y+1] ? 1 : 0)) и еще 2 на минус (если x,y не у стенки поля, естественно - некоторые переходы могут отсутствовать).

    Ищите кратчайшее расстояние из вершины (x0, y0, s[0] == grid[x0][y0] ? 1 : 0) в любую вершину с третим индексом равным l (т.е. любое место, где вы прочтете всю искомую строку). Поскольку в графе все ребра длины 1, можно запускать bfs. Граф строить и охранить не надо, можно эти 4 перехода вычислять неявно. Кладите в очередь тройки чисел, вынимайте их оттуда и вычисляйте до 4 соседних троек, которые гужно тоже сложить в очередь обхода в ширину. Удобно завести 2 костантных массива на 4 элемента, которые будут хранить приращения по x и по y в каждую их четрех сторон. Тогда не будет много дублируемого кода.

    Еще понадобится, таки, массив на n*m*l для хранения расстояния, или хотя бы пометок о том, что вершина уже в очередь была положена.
    Ответ написан
    2 комментария
  • Почему мой код считается медленным?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Ваш алгоритм работает за O(n^2). Вы для каждого числа в массиве считатете, сколько раз оно туда входит проходя по массиву через nums.count(i). Оптимальное же решение работает O(n). Надо в хеш-таблице подсчитать, сколько раз каждое число встречается, потом через алгоритм QuickSelect выбрать k-ый c конца элемент.

    Ну, или можно за O(n log n) отсортировать массив и потом за один проход подсчитать сколько раз каждое число встречается. Дальше можно второй раз отсортировать по количеству вхождений и выдать k-ый элемент. Это решение тоже пройдет.
    Ответ написан
  • Как работает замыкание в js?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Каждый вызов createCounter() создаёт и возвращает новую функцию. С которой в комплекте идёт свой новый «чемодан» замыкания, в котором лежит своя переменная counter.
    Каждый раз отдельная-новая.

    откуда берется counter при втором вызове console.log(z())

    Из того же «чемодана» от первого вызова createCounter()
    Ответ написан
    2 комментария
  • Как убрать обработчик события при вызове функции?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Если обработчик должен отрабатывать ровно 1 раз, то лучше передавать опцию once:
    box.addEventListener('mousemove', move, { once: true });
    https://developer.mozilla.org/en-US/docs/Web/API/E...
    Ответ написан
    Комментировать
  • Как сделать динамическую проверку существования ключа при создании функции?

    WblCHA
    @WblCHA
    Taulan Khatuaev, pavelpressf, потрясающие ответы с эни (нет).

    function helloFunc<T extends object, K extends keyof T>(arg: {
      nameKey: K,
      object: T
    }) {
      console.log(`Привет,  ${arg.object[arg.nameKey]}`)
    }


    https://www.typescriptlang.org/play?#code/GYVwdgxg...
    Ответ написан
    1 комментарий
  • Как превратить подстроку вида "min ( a, b )" в "a min b"?

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

    Решение поумнее, за линию:

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

    Итак, функция, опять же, проверяет, что есть min. Если нет - возвращает всю строку до первой "," или непарной ")" - нужен счетчик открытых скобок.
    В противном случае, пропускает "min", "(". Рекурсивно преобразовывает от этой позиции. Потом смотрит, что после позиции, которую вернула рекурсивная функция, лежит ",". Иначе - ошибка. Добавляет min к ответу, Рекурсивно преобразовывает оставшееся и добавляет к ответу. Проверяет, что дальше после позиции где закончила обработку рекурсивная функция лежит ")". Возвращает следующую за этим позицию.

    Можно не возвращать преобразованную строку, а сразу все функции могут просто дописывать свой ответ в какое-то одно место. А возвращать int - индекс конца. Ну, или длину обработанной части строки - так даже понятнее.
    Ответ написан
    1 комментарий
  • В чем принципиальная разница между сигнатурой индекса и утилитой Record?

    Zhuroff
    @Zhuroff Автор вопроса
    Пока удалось найти, что посредством сигнатуры можно запилить циклический тип. А Record этого не позволяет. На практике подобное вроде пока не пригождалось, но мало ли.
    type SomeType1 = { [index: string]: SomeType1 | null }
    type SomeType2 = Record<string, SomeType2 | null> // Type alias 'SomeType2' circularly references itself.
    Ответ написан
    Комментировать
  • Как вычислить мат.выражение представленное в виде дерева?

    vabka
    @vabka
    Токсичный шарпист
    Раз тут уже посчитаны приоритеты вычисления - просто рекурсивно проходишься по каждому узлу, вычисляя его.
    Ответ написан
    Комментировать
  • Алгоритм подбора параметра, чтобы подогнать ответ к заданному?

    Griboks
    @Griboks
    Всё намного проще. Вам нужно решить тривиальное уравнение вида y=kx. Ответ вас удивит...
    Ответ написан
    3 комментария
  • Base64 формат картинки, что делать на фронтенде?

    MrDecoy
    @MrDecoy Куратор тега JavaScript
    Верставший фронтендер
    что делать на фронтенде

    Пойти к бэкендеру и сказать: ты шо, дурак, зачем нам 470киллобайт не кешируемых данных по сети каждый раз гонять?!
    И пинать чтоб присылал ссылку.
    (а на деле я так понимаю там не одна картинка такая и не кешируемых данных в разы больше гоняется, что вообще ужас)

    На серьёзном хайлоад проекте это была бы, условно, смерть серверам по трафику.
    Но клиенты с не самым хорошим интернетом отлетели бы ещё раньше. А не самый хороший это даже мобильный 4g в средних условиях приёма сигнала. 470кб это очень, очень много для всего лишь одного запроса. Тяжелее запрос - дольше время до отрисовки.
    Ну и мобильный интернет далеко не у всех безлимитный. А не в России и подавно.

    А ещё есть лимиты на длину строки. В разных движках причём разные. Так что, теоритически, наверное, можно упереться в лимит строки и картинка не отобразится или будет битая.
    Ответ написан
    7 комментариев
  • Как правильно решить задачу, используя формулу комбинаторики?

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

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

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

    Покрасьте поле как шахматную доску. Черные и белые клетки. Каждая доминошка будет лежать на двух соседних белой и черной клетках. Постройте граф. Назначьте каждой клетке вершину, а ребра проведите между соседними клетками, если там нет перегородки. Граф - двудольный, ведь черные клетки окружены белыми, а белые - черными. Любое заполнение поля доминошками будет идентично паросочетанию в этом графе и наоборт. Найдите максимальное паросочетание: если оно не полное, то поле покрыть нельзя. Иначе ребра в паросочетании будут местами, куда надо класть доминошки.

    Вот статья с описанием алгоритма и реализацией.

    Это будет решение за O(n^2m^2).

    Другое решение, которое будет быстрее, если одно из измерений очень маленькое, а второе очень большое - динамическое программирование по профилю. Гуглите эти слова. Это сложнее реализовать, но зато будет работать за O(4^n m)

    Edit:
    Alexandroppolus в коментариях предложил использовать Алгоритм Хопкрофта — Карпа для поиска паросочетания, что для данного графа будет быстрее предложенного мной алгоритма Куна и будет работать за O(nm sqrt(nm)) вместо O(n^2 m^2)
    Ответ написан
    7 комментариев
  • Как в результате вычитания получить ноль максимально быстро?

    Griboks
    @Griboks
    Я долго изучал высшую математику и теперь наконец готов поделиться с вами наибыстрейшим способом получить нуль: x=0. Это даже быстрее Saboteur .
    Ответ написан
    1 комментарий
  • Как работает умножение вероятностей?

    Griboks
    @Griboks
    Всё очень просто выводится из определения вероятности: вероятность - это отношение количества благоприятных исходов к количеству экспериментов, p=n/m. Отсюда следует, что для двух независимых событий p1=n1/m1, p2=n2/m2 количество благоприятных исходов n=n1*n2 (т.е. при каждом любом благоприятном исходе события 1 нас удовлетворит абсолютно любой благоприятный исход события 2), а количество экспериментов - m=m1*m2. Тогда p=n/m=(n1*n2)/(m1*m2)=p1*p2.

    Это обычная комбинаторика. Ещё раз обращаю внимание, что для любого конкретного отдельного благоприятного исхода события 1, например #456, нас удовлетворит любой благоприятный исход события 2, например #789. Это означает, что общий исход #123 & #789 отличается от общего исхода #456 & #789, поэтому всего таких комбинаций n1*n2, а не (как вам кажется на первый взгляд) n1+n2.
    Ответ написан
    Комментировать
  • Как вычислить координату угла А прямоугольника?

    LoliDeveloper
    @LoliDeveloper
    Линейная алгебра как смысл жизни
    По моему
    Ax = Bx - length*cosC
    Ay = By - length*sinC
    Ax, Ay - координаты точки A
    C - угол
    length - расстояние от A до B
    Ответ написан
    1 комментарий
  • Как вычислить координату угла А прямоугольника?

    Тут не важны вершины C и D. Есть отрезок AB длины length под углом a, и координаты точки B. Нужна точка A.

    Наверное, всё просто:
    Ax = Bx - length * cos(a)
    Ay = By - length * sin(a)
    Ответ написан
    1 комментарий