- 779
- 712 981
3.5 задачи в неделю
Приєднався 26 бер 2016
Разбор олимпиадных задач по программированию каждые 2 дня в прямом эфире в 9 вечера по Москве.
Разбор задачи 21 leetcode.com Merge Two Sorted Lists. Решение на C++
Разбор задачи 21 leetcode.com Merge Two Sorted Lists. Решение на C++
Переглядів: 4 145
Відео
Разбор задачи 83 leetcode.com Remove Duplicates from Sorted List. Решение на C++
Переглядів 8055 років тому
Разбор задачи 83 leetcode.com Remove Duplicates from Sorted List. Решение на C
Разбор задачи 405 acmp.ru Туристическое агентство. Решение на C++
Переглядів 6467 років тому
Разбор задачи 405 acmp.ru Туристическое агентство. Решение на C
Разбор задачи 624 acmp.ru Электронная почта. Решение на C++
Переглядів 4147 років тому
Разбор задачи 624 acmp.ru Электронная почта. Решение на C
Разбор задачи 544 acmp.ru Мячик на лестнице. Решение на C++
Переглядів 2,1 тис.8 років тому
Разбор задачи 544 acmp.ru Мячик на лестнице. Решение на C
Разбор задачи 227 acmp.ru Сломанный калькулятор. Решение на C++
Переглядів 2,3 тис.8 років тому
Разбор задачи 227 acmp.ru Сломанный калькулятор. Решение на C
Разбор задачи 682 acmp.ru Сумма n-значных чисел. Решение на C++ Java Python C#
Переглядів 2,3 тис.8 років тому
Разбор задачи 682 acmp.ru Сумма n-значных чисел. Решение на C Java Python C#
Разбор задачи 230 acmp.ru Луч света в темном царстве. Решение на C++
Переглядів 5178 років тому
Разбор задачи 230 acmp.ru Луч света в темном царстве. Решение на C
Разбор задачи 37 acmp.ru Сжимающий оператор. Решение на C++
Переглядів 8198 років тому
Разбор задачи 37 acmp.ru Сжимающий оператор. Решение на C
Разбор задачи 483 acmp.ru Двоичная машина. Решение на C++
Переглядів 3658 років тому
Разбор задачи 483 acmp.ru Двоичная машина. Решение на C
Разбор задачи 164 acmp.ru Счастливый билет - 2. Решение на C++
Переглядів 1,9 тис.8 років тому
Разбор задачи 164 acmp.ru Счастливый билет - 2. Решение на C
Разбор задачи 455 acmp.ru Умножение дроби. Решение на C++
Переглядів 5248 років тому
Разбор задачи 455 acmp.ru Умножение дроби. Решение на C
Разбор задачи 216 acmp.ru Коллекционирование этикеток. Решение на C++
Переглядів 9418 років тому
Разбор задачи 216 acmp.ru Коллекционирование этикеток. Решение на C
Разбор задачи 261 acmp.ru Лотерея. Решение на C++
Переглядів 6558 років тому
Разбор задачи 261 acmp.ru Лотерея. Решение на C
Разбор задачи 664 acmp.ru Котлеты и дополнение по задаче 261 acmp.ru Лотерея. Решение на C++
Переглядів 3,3 тис.8 років тому
Разбор задачи 664 acmp.ru Котлеты и дополнение по задаче 261 acmp.ru Лотерея. Решение на C
Разбор задачи 437 acmp.ru Тапкодер. Решение на C++
Переглядів 6838 років тому
Разбор задачи 437 acmp.ru Тапкодер. Решение на C
Только что решил задачу на Python. Посмотрел и оказалось, что я единственный, кто это сделал, за 9 лет. Спасибо Вам за ваши ролики, по ним решил уже очень много задач. В этом году заканчиваю школу и надеюсь все-таки выйти на всеросс. Если сделаю это, то точно благодаря ещё и Вам! P. S. Если возможно, было бы хорошо поднять ограничения по времени в этой задаче, чтобы её можно было решить с правильной идеей, но без бесконечных оптимизаций не только на с++, но и на Python
@@Pepega230 напишите мне на почту (есть в описании видео) код решения этой задачи на Питоне, который Вы считаете простым - и который должен зайти за одну секунду на Питоне или PyPy. С этим кодом будем обсуждать с администратором acmp возможность увеличения памяти и возможно времени под этот код. Обычно администратор идёт навстречу в плане увеличения памяти.
спасибо, практически сам додумался
Добрый день, а почему вы решили итерацией, а не рекурсией. Если правильно понял, то решение должно быть именно рекурсионным, так как задача относится к DP
@@hIKipau В большинстве задач ДП решение итерацией более экономное в плане ресурсов и более быстрое, поэтому я почти всегда пишу итерацией. Исключение - когда далеко не все состояния нужно вычислить для получения ответа. Тогда рекурсия может выиграть.
А без векторов слабо ? )
@@tochechka3_3 если Вам задали написать решение этой задачи на чистом Си и Вы не можете реализовать - можете обратиться ко мне, и я напишу Вам за отдельную плату.
Спасибо вам за объяснение этой задачи, я попробую переделать ее сам ❤
лучший
все просто и доходчиво, спасибо!
Если задача состоит именно в перевороте цифр, то ничего не изменится, кроме их написания. Хотя, любопытно было бы это реализовать!
спустя 4 года, смотрю и благодарю вас всё сильнее, без вас мои руки бы давно упали!)
О Боже! Насколько это гениально!
Шикарное объяснение, спасибо!
Спасибо, прозрачный красивый разбор)
начало 4:30
Йоу.... Круто, спасибо. Сам не додумался..
Спасибо!
Сложное условие
Если не менять сигнатуру метода, то можно совсем обойтись без доп памяти - записывая результат в первый элемент массива.
@@Gesperid обычно не пишут O(0), потому что есть расходы памяти на всякие мелочи: вызов метода (но для inline возможно нет расхода), переменная цикла for (но для while нет расхода).
круто
Кто этот легендарный Игорь Андриянов?
@@Gesperid главный специалист по олимпиадному программированию в Вологодском государственном университете
Здрасьте. Не будет там никогда пустой подпоследовательности. Кроме всего прочего, там не будет прогресии в случае, если разница =0. Тесткейс, кажется, 52, из нулей и единиц. Правильнй ответ 306. 306 нулей.
из обновлений: наивное решение падает даже с ускоренеим: const int ZERO = [](){ ios_base::sync_with_stdio(false); cin.tie(nullptr); return 0; }(); class Solution { public: int maxProfit(const vector<int>& a) { int ans = 0; for (int i = 0; i < (int)a.size(); i++) { for (int j = i + 1; j < (int)a.size(); j++) { ans = max(ans, a[j] - a[i]); } } return ans; } };
Более компактное решение: bool isLongPressedName(string name, string typed) { int j = 0; char prev = '#'; for (char c: typed) { if (name[j] == c) { ++j; } else if (prev != c) { return false; } prev = c; } return (j == name.size()); }
23:20 я сделал почти как у вас, только ans.push_back(vector<int>(size)); вместо reserv'a. Это позволяет добавлять вершины в 26 строчке через ans[level][i]=node->val; что крайне полезно для задачи 103 обход зигзагом. Вопрос - что быстрее работает? Пуш-бек вектора нужной длины или резерв и пуш-бек по одному элементу как у вас. Спасибо за обзор!
По сути и при push_back вектора, и при reserve, и при resize происходит примерно одно и то же выделение памяти, остальные детали зависят от оптимизатора, так что что быстрее теоретически сказать невозможно. Плюс-минус без разницы.
Если вам дали эту задачу на интервью - вас не хотят нанимать (c) leetcode 27:04 вопрос - в чем разница есть ли параметр const у ссылки или нет? Я думал что это больше для удобства программиста, и на скорость работы программы не влияет
Либо спрашивает человек, который и на квадрат согласен. Разница в const у ссылки - если const есть, то все методы объекта, не помеченные const, то есть изменяющие состояние объекта, не разрешено вызывать.
@@35zvn Спасибо. На собеседованиях обычно минут 15 дают на задачу, насколько я знаю, если уж человек который пол жизни спортивным программированием занимается и учебники пишет ее полчаса решал, думаю 95% людей тут и отвалится. Под видео конкурентов очень многие писали что эту задачу 2-4 дня решали
Спасибо. Вопрос - зачем во втором способе 16:52 ассерт, если 20 строка его исключает ?
Ну так для этого assert и нужен - чтобы никогда не срабатывал. Помогает формулировать, что мы знаем о программе и конкретных точках исполнения.
Ограничения (значения элементов от 0 до 1000) позволяют завести статический массив int count[1001] вместо использования map. С assert, вроде бы, нужно еще дополнительно в скобки заключить условное выражение.
Посмотрите на видео условие задачи, есть ли там ограничение. Они на leetcode не всегда были. Возможно именно их отсутствием объясняется использование map
Странно, что не упомянули про полиномиальные хеши
А какие преимущества у них по сравнению с КМП? Разве что память можно в алгоритме Рабина-Карпа получить O(1). Но минус существенный - есть вероятность, что ответ будет неверный, что имеет смысл терпеть только если алгоритмическая сложность улучшается (обычно по времени), но конкретно тут мы этого не наблюдаем, КМП и так за линию работает. Забавный факт: поиск подстроки в строке на Go делается с помощью хэшей, так что если реализовать наивное решение на Go - оно будет соответствовать Вашему предложению.
@@35zvnПолиномиальные хеши не имеют преимуществ (с точки зрения асимптотической сложности), но их легко запомнить, и они подходят под большее число задач. В условиях стресса, первое, что приходит на ум в задачах со строками, это хеши, и скорее всего, с ними можно решить задачу. Получается своего рода запасной вариант, который почти всегда спасает.
Классный способ! Все что до этого видел были через рекурсию с использованием кеша
У меня при просмотре вашего видео в голову пришло немного другое решение, тоже с переподвешиванием (хотя оно может быть то же самое, но переподвешивается с другой стороны). Идея: если у нас есть левое поддерево, раскручиваем его (делаем ротации) до тех пор, пока не вытолкнем в корень самый левый лист. После этого у корня не будет левого сына (потому что он раньше был самым левым листом). Тогда спускаемся в правое поддерево и делаем с ним то же самое. Можно это реализовать также с O(1) памяти. Для этого хранить родителя текущего поддерева. А именно: * Пусть root - корень текущего поддерева * prev - родитель root-а. Инвариант: prev либо nullptr (если root - корень всего дерева), либо у prev нет левого сына (мы уже его раскрутили). Тогда мы знаем, что root является правым сыном, и при ротациях будем обновлять prev->right. * Раскручиваем текущее поддерево пока есть левый сын. * Если левого сына нет: делаем prev = root и спускаемся в правое поддерево (root = root->right). * Так делаем до тех пор, пока есть правый сын. Вроде бы, получившийся алгоритм имеет ту же асимптотику, что и dfs, потому что по каждому ребру мы идем не более, чем два раза (из root в root->left, это ребро становится правым после ротации, потом из root в root->right, но после того, как мы ушли в правое поддерево, мы уже никогда не пройдем по этому ребру). Получился такой код: TreeNode* increasingBST(TreeNode* root) { TreeNode *prev = nullptr; TreeNode *ans = nullptr; while(root) { if (root->left) { auto left_right = root->left->right; auto left = root->left; left->right = root; root->left = left_right; root = left; if (prev) prev->right = root; } else { if (!ans) ans = root; prev = root; root = root->right; } } return ans; }
Задача 78 это расширение задачи leetcode 77, чтоб разобраться с ее рекурсивным решением лучше 77 первой решить.
спасибо за видео, благодаря таким как вы зарождаются таланты!
Красивое решение и что самое главное, в разы понятнее чем то, что написано на самом литкоде во вкладке solution.
Обожаю после решения задачи на leetcode найти ее на этом канале и посмотреть все возможные варианты ее решения, с подробным разбором. Спасибо за труд :) 21:04 Нубский вопрос: зачем делать move, если это и так последняя строка в функции и память занятая хеш таблицей сама скоро освободится?
Вопрос не в освобождении памяти. Она конечно освободится и без move. С move НЕ будет дополнительных расходов на новую копию данных в ответе. В C++ когда Вы один vector копируете в другой, идёт полное копирование данных. В отличие от например list в Python, где при присваивании создаётся ссылка на тот же объект.
29:14 А почему reverse, а не sort? reverse быстрее работает чем sort?
Reverse за O(n), sort за O(nlogn). Разница не очень большая, но есть.
@@35zvn Спасибо. А вообще ты оч. крутой, быстро задачки решаешь. Я бы тебя нанял :D
отличное объяснение
Спасибо большое за разбор, сам додумался только до первого метода, интересно было узнать иные
Хотелось бы увидеть решение этой задачи на чистом С :)
Мне тоже 😉
@@35zvn мне не удалось на си просто перенести твой алгоритм, там нет ни векторов ни наборов, пришлось разбираться что такое DFS. Может надо кому: char *num_to_string(char num) { switch (num) { case '2' : return "abc"; case '3' : return "def"; case '4' : return "ghi"; case '5' : return "jkl"; case '6' : return "mno"; case '7' : return "pqrs"; case '8' : return "tuv"; case '9' : return "wxyz"; default: return ""; } } void backtrack(int K, char cur_str[5], char* s, const int strlen_s, char **result, int *return_size) { char str[5]; strcpy(str, cur_str); if (K == strlen_s) //Условие выхода из рекурсии - перебрали все цифры { strcpy(result[(*return_size)++], str); return; } for (int i=0; i< strlen(num_to_string(s[K])); i++) { str[K] = num_to_string(s[K])[i]; //Перебираю по порядку все буквы для текущей K цифры str[K+1] = '\0'; //Надо делать каждый раз, иначе strcpy: buffer overflow detected backtrack(K+1, str, s, strlen_s, result, return_size); //Перехожу к следующей цифре } } char** letterCombinations(char* s, int* return_size) { int strlen_s = strlen(s); int capacity; *return_size=0; switch (strlen_s) { case 1 : capacity=4; break; //capacity = 4^n. Всего возможно комбинаций (кол-во букв в цифре)^всего цифр case 2 : capacity=16; break; case 3 : capacity=64; break; case 4 : capacity=256; break; default: return NULL; } char **result = (char **)malloc(capacity*sizeof(char *)); //Выделение памяти под массив указателей на строки for(int i = 0; i < capacity; i++) result[i] = (char*) malloc(sizeof(char) * 5); //Выделение памяти под сами строки длиной 5 символов backtrack(0, "", s, strlen_s, result, return_size); return result; }
Спасибо!
ничего не понятно
9:32 ))
Лучший
что бы я без Вас делал...
вау, круто!
А почему на 7:43 мы ставим (int) и что он будет делать в этом случае? Почему без этой приписки код работает, но медленнее?
Без этого (int) сравнение int и size_t будет в size_t, конкретно тут проблемы в этом нет, но если бы было какое-то выражение вроде size() - 1 и при этом size() мог быть равен 0 - такое сравнение было бы ошибочно. Поэтому приведение к int тут просто относится к культуре написания кода с минимальной вероятностью ошибки. Что касается медленного кода - скорее всего замеры leetcode не точны, и такое заявление можно делать только после десятка раз сдачи того и другого кода.
С матрицами, конечно, решение, что с первого раза и не поймешь))) спасибо.
А где ссылка на код?
А её нет, чтоб не сдавали, не разобравшись
Все эти задачи просто заставляют нас тратить своё время впустую, вместо того, чтобы реально работать и зарабатывать деньги для своей семьи. Какой смысл от того, что я решу все эти задачи сам? из всего, что я решал на leetcode или acmp мне в работе попалось только 3- 4 (поверхностно) Это при том, что на одну задачу со сложностью до 50 процентов я трачу около суток .Преподаватели, которые требуют такие задачи вообще в курсе, как работает бизнес, что требуют заказчики и какие задачи они ставят и за что платят деньги? Потратил на решение этих лабораторных почти две недели, а результат? лучше стал понимать алгоритмы и динамическое программирование? нет. Потому что в работе совсем другое используется...
@@aleksey4uk это зависит от того, что именно Вы делаете на работе. Когда я работал в игровой индустрии, совсем ничего из олимпиад было не нужно. Когда писал программы для видеокарт с синхронной работой тысяч медленных исполнителей - вот тут подобные вещи оказываются крайне нужны.
А почему нельзя взять r = max(h, w) * n?
Можно. Вопрос в типе данных, который потребуется для вычислений.
Смесь второго и третьего варианта хорошо сделать без swop. a[j]=a[i]; a[i]=0; две операции вместо трех.
Великий человек на авторе, и код поможет написать, и решение подробное расскажет. Я искал разборы от авторов задач, но нашел золото!
пашол у пезду дура сукаа в описании решение надо оставлять
55:53 Ахаха, запатентованная методика подгонометрии.