Тренировки по алгоритмам от Яндекса. Лекция 5: «Префиксные суммы и два указателя»

Поділитися
Вставка
  • Опубліковано 13 чер 2021
  • Расписание тренировок доступно по ссылке: yandex.ru/yaintern/algorithm-...
    Чат в Телеграме для общения и вопросов о тренировках: t.me/joinchat/Ve7wRegrZtI0NjIy

КОМЕНТАРІ • 61

  • @4r4zzz
    @4r4zzz Рік тому +14

    Как же хорошо заходит такой формат... спасибо большое за подробные объяснения и легкость языка! Это лучшие качества для человека, который обучает других.

  • @alexanderantropov2106
    @alexanderantropov2106 Рік тому +33

    0:19 Префиксные суммы
    2:42 Построение массива префиксных сумм
    8:02 Ответ на запрос суммы на отрезке (Range Sum Query)
    10:26 Реализация RSQ через префиксные суммы
    13:26 Задача №1
    13:49 Решение за O(NM)
    14:42 Решение за О(N + M)
    17:04 Задача №2
    17:38 Решение за O(N^3)
    19:30 Решение за O(N^2)
    21:02 Решение за O(N)
    26:24 Два указателя
    26:35 Задача №3
    28:18 Решение за O(N^2)
    29:54 Решение за O(N)
    36:56 Задача №4
    38:00 Решение
    46:06 Задача №5
    48:19 Неидеальная реализация
    51:20 Более близкая к идеалу реализация
    53:00 Ответы на вопросы

  • @egorkalmykov4003
    @egorkalmykov4003 2 роки тому +3

    Спасибо огромное за информативную и полезную лекцию !!!

  • @Velichkina_a
    @Velichkina_a 2 роки тому +1

    Очень здорово, мне нравится понятность и доступность :)

  • @user-ue4zz1bd4r
    @user-ue4zz1bd4r 7 місяців тому +1

    Хорошая лекция. Хорошо донесли материал

  • @lifeisbeautifu1
    @lifeisbeautifu1 Рік тому

    Большое вам спасибо!

  • @alexanderantropov2106
    @alexanderantropov2106 Рік тому +20

    Сразу не совсем понял, почему количество пар равно n * (n - 1) // 2.
    Количество способов, которыми можно выбрать k элементов из n элементов (n choose k), определяется по формуле n! / (k! * (n - k)!)
    Для k = 2 (выбор пары): (n * (n -1) * (n - 2)!) / (2! * (n - 2)!) = (n * (n - 1)) / 2

  • @yobniares
    @yobniares Рік тому +1

    узнал про последовательную обработку условий при операции and после частого парса json (проверял есть ли такой ключ и по нему нужное условие), а не из-за хорошего обучения)

  • @alexanderantropov2106
    @alexanderantropov2106 Рік тому +6

    Мне кажется, что в задаче 4 на 45:06 можно опустить условие 'first == last'. Так как в этом случае всегда выполнится второе условие: если оба указывают на число A, то A плюс большее число всегда больше А

    • @Nazaro4ka
      @Nazaro4ka Рік тому

      Пошел в комменты чтобы найти твой коммент

    • @user-mf2dz8cq3w
      @user-mf2dz8cq3w Місяць тому

      Контрпример: lst= [1, 100], k=4. на второй итерации for у тебя first будет указывать на 100. lst[first+1] выдаст ошибку IndexError - выход за границы массива

  • @user-mz8fw2mw6q
    @user-mz8fw2mw6q Рік тому

    Ой, крутой мужик, я у него на курсерии питону училась

  • @RomanTokarenko
    @RomanTokarenko Рік тому +10

    А правильно ли задача 2 сформулирована? Такое ощущение, что вы ищете ответ на вопрос "сколько подотрезков, полностью заполненных нулями, есть в последовательности", а не на вопрос "сколько подотрезков с нулевой суммой есть в последовательности"

  • @indagadir
    @indagadir Рік тому +2

    26:28 начало части про 2 указателя

  • @ilyachudakov7944
    @ilyachudakov7944 Рік тому

    Почему используете так часто list, вроде как dict работает гораздо быстрее?

  • @jez_ass2317
    @jez_ass2317 Рік тому

    Формула подсчёта допустимых отрезков неверна. Если у нас в последовательности встречается 0, то префиксная сумма будет повторяться, а следовательно, будет увеличиваться значение в словаре, но когда мы попытаемся посчитать количество возможных отрезков, то получим неверный ответ, так как отрезки, состоящие ТОЛЬКО из числа и 0 мы брать не можем.

  • @user-ww9qj5jx9g
    @user-ww9qj5jx9g Рік тому +2

    2 вопроса (начало видео):
    1. Сказано, что чтобы посчитать сумму с (n; m) для одномерного массива, будет сложность O(N^2), с помощью префиксных сумм - O(N). Разве сложность при подсчёте простым перебором не будет ли O(N) (т.к. достаточно всего одного цикла для одномерного массива), а при подсчёте префиксными суммами - O(const) ?
    2. Чтобы создать массив из префиксных сумм, нам нужно пробежаться по данному массиву в любом случае, т.е. затратить время на это. Тогда в чем мы выиграем, если по сравнению с простым перебором массива?

    • @HelloWorld-oc2eu
      @HelloWorld-oc2eu Рік тому

      Вопрос в топ! Тоже данный вопрос возник

    • @user-sf9ow6ir3o
      @user-sf9ow6ir3o Рік тому

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

    • @kycb345
      @kycb345 3 місяці тому

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

  • @about_books_channel
    @about_books_channel Рік тому

    Почему нельзя так решить последнюю?
    def s(s1, s2):
    """Даны две отсортированные последовательности, необходимо свести их в одну отсортированную"""
    ans = []
    sym = 0
    for i in s1:
    while sym < len(s2) and s2[sym]

    • @user-th8bg8yy2j
      @user-th8bg8yy2j Рік тому +3

      потому что если наибольшие элементы содержатся в s2, то они не будут добавлены в ans. Попробуйте прогнать программу например для s1 = (1, 3, 5); s2 = (2, 4, 6, 7, 8)

  • @vasilysukhanov6913
    @vasilysukhanov6913 2 роки тому

    по поводу пефикса сумма хорошо бы пояснение написать почему количество интервалов N*(N-1)/2, лучше написать и доказательство через матрицу смежности неориентированного графа, там эта формула выводится интуитивно

    • @NaiLies_
      @NaiLies_ 2 роки тому +7

      Мне показалось, что намного проще сказать что это число сочетаний из N по 2, где N это количество ячеек с одинаковой префиксной суммой (выбираем по 2 ячейки из N всеми возможными способами)

  • @karatemoscow
    @karatemoscow 2 роки тому +1

    1:01:32 не понял все равно почему сложность O(N)? там же два цикла for а затем while?

    • @user-dv7yl6kg8y
      @user-dv7yl6kg8y 2 роки тому +5

      потому что внутренний цикл выполняется не каждый цикл N раз, а только за все циклы N раз и сложность получается O(N+N) = O(N)

  • @avdim88
    @avdim88 2 роки тому +1

    В JavaScript внутри if(some && boolean || logic) выполняются все выражения, и поэтому условие считается целиком.

    • @MRbahoo08
      @MRbahoo08 2 роки тому +6

      Потому что тут есть операция "или"

  • @aleksandrkobelev8868
    @aleksandrkobelev8868 Рік тому

    ничего не понял, но очень интересно

  • @alexanderantropov2106
    @alexanderantropov2106 Рік тому +1

    Вот решение 2 задачи с нулевой суммой на JS за один проход и без использования комбинаторной функции:
    const sumCount = { 0: 1 };
    let sum = 0;
    let zeroCount = 0;
    for (let i = 0; i < nums.length; i++) {
    sum += nums[i];
    if (!sumCount[sum]) {
    sumCount[sum] = 0;
    }
    zeroCount += sumCount[sum];
    sumCount[sum] += 1;
    }
    console.log(zeroCount);

    • @TheRunnerSVO
      @TheRunnerSVO Рік тому

      Считаешь количество нулей,а не количество возможных последовательностей с нулевой ссуммо. Другую задачу решает его алгоритм

  • @RomanTokarenko
    @RomanTokarenko Рік тому

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

  • @TheRunnerSVO
    @TheRunnerSVO Рік тому +1

    Вставлю свои пять копеек реализации псевдодвух указателей в слияние списка
    def merge(arr, arr2):
    index1 = index2 = 0
    res = []
    while index1 < len(arr) and index2 < len(arr2):
    if arr[index1] = arr2[index2]:
    res.append(arr2[index2])
    index2 += 1
    return res + arr[index1:] + arr2[index2:]

    • @mberdyshev
      @mberdyshev Рік тому

      Ваша программа отработает неверно на примере [1, 2, 5], [4]

    • @TheRunnerSVO
      @TheRunnerSVO Рік тому +1

      @@mberdyshev Поправил))

  • @timanb2491
    @timanb2491 2 роки тому +1

    почему когда мы используем for и затем while то сложность О(n)? Два же цикла должна быть О(n^2)

    • @vasilysukhanov6913
      @vasilysukhanov6913 2 роки тому +3

      очень просто, тут на самом деле нет двух циклов, главный цикл это while, а for просто позволяет получить следующий first, таким образом тут нет вложенности, для каждого first не выполняется while по всем N, если точно, то for и while дают O(N+N), таким образом O(N). Посмотрите последовательность для k = 3 [0,4,8,12,16,20,24] и [0,4,4,4,4,4,4,4]

    • @user-mz8fw2mw6q
      @user-mz8fw2mw6q Рік тому +1

      Солнце мое, мы же границу перебора двигаем, в итоге мы только N чисел и переберём

  • @raphaelosipov867
    @raphaelosipov867 2 роки тому +17

    На мой субъективный взгляд, первые 4 лекции все было понятно и просто, как и положено обучающему материалу. А вот понятность, прозрачность и подробность 5ой лекции около нуля. И судя по комментариям, я тут такой не один:)

  • @nikprilutskiy7064
    @nikprilutskiy7064 Рік тому

    Что-то я не понял, если префиксная сумма это "текущий + предыдущий", то почему у нулевого элемента со значением 5 префиксная сумма ноль, а не пять?

    • @nikprilutskiy7064
      @nikprilutskiy7064 Рік тому +2

      сам уже понял, это из-за подхода не включения крайнего правого символа в массив)

  • @vanechka6011
    @vanechka6011 Рік тому

    В задаче 1. Первая реализация выполняется за время O(N*M). Почему не за O(N + M)? Мы же не проходимся по всем элементам снова.

    • @mberdyshev
      @mberdyshev Рік тому

      Худший случай, когда все M запросов запрашивают интервал (0; N-1). В таком случае в каждом запросе будет итерироваться весь список длиной N. Отсюда, и сложность O(M*N)

    • @gotrax2661
      @gotrax2661 Рік тому

      @@mberdyshev а чем является m в данном случае?
      Не совсем понимаю, почему 1 решение в 1 задачи, это не O(N), если по сути наш отрезок от l до r только в худшем случае будет равен длине последовательности, то есть по сути сложность должна быть O(N). Можете объяснить, пожалуйста

    • @mberdyshev
      @mberdyshev Рік тому

      @@gotrax2661 - это количество запросов, дано по условию задачи.
      Всё правильно, в данной реализации в худшем случае мы тратим O(N) операций на один запрос. Так как всего M запросов, то и получаем общую сложность O(N * M).

    • @konstantin6043
      @konstantin6043 9 місяців тому

      @@gotrax2661 Насколько я понял, О-большое и описывает всегда худший случай.

  • @vanechka6011
    @vanechka6011 Рік тому

    В задаче 4. Тест 1 2 3 4 5 должен выдавать 15. Используя вашу реализацию получается 14

    • @mberdyshev
      @mberdyshev Рік тому

      Если для теста [1, 2, 3, 4, 5] ответ был бы 15, то тогда нужно задействовать всех игроков. Но сумма слабейших меньше сильнейшего (1+2 < 5), что не соответствует условию задачи.
      Для ответа 14, который получается при игроках [2, 3, 4, 5] условие задачи соблюдается (2 + 3 ≥ 5)

    • @freesx1306
      @freesx1306 7 місяців тому

      @@mberdyshev [1, 1, 3, 3, 4, 6, 11] для такого набора из видео выдаёт 17, а должно 16 ( 3 + 3 + 4 + 6)

    • @freesx1306
      @freesx1306 7 місяців тому

      а отмена, о берет игроков 6 и 11, сравнивая их между собой, тогда понятно

  • @RisDeep
    @RisDeep 2 роки тому +18

    Эта лекция мне плохо далась

    • @Genialbonehead
      @Genialbonehead 2 роки тому +3

      Аналогично, но чую что надо пересмотреть и всё же вникнуть

    • @user-mz8fw2mw6q
      @user-mz8fw2mw6q Рік тому +2

      Я пересматривала задачи по нескольку раз, чтобы идею и реализацию связать
      Не боись, ты не одинок, только олимпиадники, наверное, смогут без повтора смотреть, потому что половину уже знают

  • @user-do4su2wy3z
    @user-do4su2wy3z 2 роки тому +1

    А для чего это?
    Ведь проще написать так:
    a = [1,5,2,5,2,5,23,6]
    #Найдем сумму от 3 элемента до 6:
    s = 0
    for i in range(3,6):
    s += a[i]
    print(s)
    Чем писать так:
    prefsum = [0] * (len(a) + 1)
    for i in range(1, len(a) + 1):
    prefsum[i] = prefsum[i - 1] + a[i - 1]
    print(prefsum[6] - prefsum[3])

    • @user-og2oc5kw8p
      @user-og2oc5kw8p 2 роки тому +4

      в лекции говорили о том, что если необходимо делать такой подсчёт не один раз, а постоянно, то каждый раз считать суммы (как первом варианте) будет медленнее, чем хранить их и вычислять разность одним действием (как во втором варианте)

    • @user-do4su2wy3z
      @user-do4su2wy3z 2 роки тому

      @@user-og2oc5kw8p Спасибо) Почему-то мне не очень нравятся уроке от Яндекса. Я нашел другое видео, в котором объяснение более понятное, информации больше и показали интересные задачи, в которых используется префиксная сумма.

    • @user-do4su2wy3z
      @user-do4su2wy3z 2 роки тому

      @@user-og2oc5kw8p Хотя курс по питону от данного преподавателя на курсере мне понравился.

    • @user-og2oc5kw8p
      @user-og2oc5kw8p 2 роки тому

      @@user-do4su2wy3z там раскрыта только эта тема или есть ещё какие-то видео по алгоритмам?)

    • @user-do4su2wy3z
      @user-do4su2wy3z 2 роки тому

      @@user-og2oc5kw8p вы про видео, которое я смотрел? Там еще рассказали про двумерные преф. суммы, трехмерные и всякие другие штуки.