/yaalgo

Набор задач и решений, подготовка по секции алгоритмики к интервью с ya

Primary LanguageKotlin

Примеры задач для подготовки к ТО

linked lists:

binary search:

Тут все максимально просто, бинарный поиск и в африке бинарный поиск. Последние три - поиск точки сдвига с помощью модифицированного алгоритма бинарного поиска.

hash table:

Тут тоже все просто, хэш таблицы есть хеш таблицы.

Постановка задачи выше: дан массив из n целочисленных значений. Одно из значений уникально, остальные встречаются ровно два раза. Найти уникальное значение. Вообще, с помощью хеш таблиц за O(1) эту задачу не решить. За O(1) по памяти и O(N) по операциям решить можно, перексорив все числа в массиве, потому что A xor A = 0, A xor 0 = A.

Задачи на анаграммы имеют схожие решения с суммами. Но, что-то мне подсказывает, что более лучшим варинтом будет закодировать буквы простыми числами (A - 2; B - 3; C - 5; D - 7 и т.п.) и представлять анаграммы как сумму кодированных символов, умноженных на число их повторений + (отдельно, не как сумма) - количество символов в строке. Тогда, к примеру, DACA = 7 + 5 + 2*2 [4] = 16 [4]. К сожалению, отсутствие нормального математического бэкграунда не дает мне возможности составить доказательство этой гипотезы.

queue/stack:

  • https://leetcode.com/problems/valid-parentheses/ - брр, берем стек и хэш таблицу, в хеш таблицу закидываем скобки, где ключ - закрывающая скобка из пары. Затем пушим в стек символы. Если очередной символ является ключом для символа на вершине стека, то выполняем pop и скипаем этот элемент. Если после прогона всей строки в стеке остались значения, то строка невалидная.

dfs/bfs:

  • https://leetcode.com/problems/number-of-islands/ - простая задача, по идее, берем и проходимся по массиву в каком-либо определенном порядке, как только натыкаемся на единичку - производим поиск в ширину или до тех пор, пока его возможно производить, изменяя значения посещенных вершин с 1 на ноль. Каждый раз, когда мы в головном цикле натыкаемся на 1-ку, инкрементируем счетчик островов.
  • https://leetcode.com/problems/remove-invalid-parentheses/ - достаточно сложная проблема, 6 утра, понедельник, скипаю. Основная сложность для меня - непонятно, как данную последовательность представить в виде графа и свести решения к поиску в глубину или ширину.

sort:

  • https://leetcode.com/problems/merge-intervals/ - Тут все просто. Для начала берем и отсортировываем массивы qsort'ом, затем просто проходимся по отсортированному массиву и применяем следущий подход:
  1. Если выходной массив пуст - добавляем первый элемент из массива интервалов, записываем в переменную конец интервала.
  2. Если массив имеет элементы:
  • A: если начало интервала больше чем переменная, то назначаем переменной значение, равное концу интервала и добавляем в выходной массив этот элемент.
  • B: если начало интервала меньше или равно значение переменной, то, в случае, если конец интервала больше переменной, то устанавливаем значение переменной равным значению конца интервала, в противном случа - просто скипаем.

Скорость решения равна: O(N log N) qsort + O(N) перебора = O(N log N + N) = O(N log N)

heap/hash:

Все просто, берем HashMap и добавляем туда значения в качестве ключей, а в качестве значения - счетчик. Если значение уже есть в таблице - то увеличиваем счетчик. Затем сортируем набор пар по значению и отдаем. Связка HashMap и PriorityQueue.

two pointers:

  • https://leetcode.com/problems/container-with-most-water/ - скользящее окно наоборот, устанавливаем левую и правую границу и поочередно сближаем их, перезаписывая площадь в случае, если она увеличилась. Main.maxSquareTask()
  • https://leetcode.com/problems/partition-labels/ - как решить двумя указателями - придумать не могу. Максимум, что приходит на ум:
  1. взять первый символ и найти последнее его вхождение в строку
  2. взять следующий уникальный символ и повторить Повторять до тех пор, пока в подстроке не останется новых символов. По идее, это уже O(N^2). Уже неплохо. Как варинт, можно ускорить все это засчет реестра первых и последних вхождений, единоразово пройтись по строке, и сформировать очередь (Deque), где каждый элемент это координаты первого и последнего вхождения для каждого символа. Частичное решение в Main.longestLabels() (решение отвечает только на вопрос, сколько таких подстрок)

sliding window:

Никогда ничего не писал с использованием динамических алгоритмов. Понимаю только общую суть. Первые два, по идее, решаются с помощью priority queue. Правда, не вижу тут динамического программирования, кроме того, что присутствует скользящее окно. Третье - хз.

tree:

Тут конкретный пробел. По факту, знаю только две структуры на деревьях - черно-красное дерево (TreeMap) и бинарное дерево (куча) (PriorityQueue).

greedy problems:

Никогда не решал NP полные задачи жадными алгоритмами. В целом, подход простой, определить оптимальную локальную стратегию и применить её к общей задаче.