C/C++ | LeetCode
Відкрити в Telegram
Cайт easyoffer.ru Реклама @easyoffer_adv ВП @easyoffer_vp Тесты t.me/+zYofcX2VLTM3MGMy Вопросы собесов t.me/+BTbqlW1VbIFmYmVi Вакансии t.me/+za2mJYs4riAzMzFi
Показати більше3 259
Підписники
Немає даних24 години
-17 днів
-430 день
Архів дописів
3 259
Задача: 1260. Shift 2D Grid
Сложность: easy
Дана двумерная сетка размером m x n и целое число k. Требуется сдвинуть сетку k раз. За одну операцию сдвига: элемент в grid[i][j] перемещается в grid[i][j + 1]. Элемент в grid[i][n - 1] перемещается в grid[i + 1][0]. Элемент в grid[m - 1][n - 1] перемещается в grid[0][0]. Верните двумерную сетку после применения операции сдвига k раз.
Пример:
Input: grid = [[1,2,3],[4,5,6],[7,8,9]], k = 1 Output: [[9,1,2],[3,4,5],[6,7,8]]👨💻 Алгоритм: 1⃣Преобразовать двумерную сетку в одномерный массив. 2⃣Выполнить сдвиг элементов в одномерном массиве. 3⃣Преобразовать одномерный массив обратно в двумерную сетку. 😎 Решение:
class Solution {
public:
vector<vector<int>> shiftGrid(vector<vector<int>>& grid, int k) {
int m = grid.size(), n = grid[0].size();
int total = m * n;
k = k % total;
if (k == 0) {
return grid;
}
vector<int> flatArray(total);
for (int i = 0; i < total; ++i) {
flatArray[i] = grid[i / n][i % n];
}
vector<int> newArray(total);
for (int i = 0; i < total; ++i) {
newArray[(i + k) % total] = flatArray[i];
}
vector<vector<int>> newGrid(m, vector<int>(n));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
newGrid[i][j] = newArray[i * n + j];
}
}
return newGrid;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 473. Matchsticks to Square
Сложность: medium
Дано целочисленный массив спичек, где matchsticks[i] — это длина i-й спички. Необходимо использовать все спички для создания одного квадрата. Нельзя ломать никакую спичку, но можно соединять их, при этом каждая спичка должна быть использована ровно один раз.
Вернуть true, если можно составить квадрат, и false в противном случае.
Пример:
Input: matchsticks = [1,1,2,2,2] Output: true Explanation: You can form a square with length 2, one side of the square came two sticks with length 1.👨💻 Алгоритм: 1⃣Определяем рекурсивную функцию, которая принимает текущий индекс обрабатываемой спички и количество сторон квадрата, которые уже полностью сформированы. Базовый случай для рекурсии: если все спички использованы и сформировано 4 стороны, возвращаем True. 2⃣Для текущей спички рассматриваем 4 варианта: она может быть частью любой из сторон квадрата. Пробуем каждый из 4 вариантов, вызывая рекурсию для них. 3⃣Если какой-либо из рекурсивных вызовов возвращает True, возвращаем True, в противном случае возвращаем False. 😎 Решение:
#include <vector>
#include <algorithm>
class Solution {
public:
std::vector<int> nums;
std::vector<int> sums;
int possibleSquareSide;
Solution() : sums(4, 0) {}
bool dfs(int index) {
if (index == nums.size()) {
return sums[0] == sums[1] && sums[1] == sums[2] && sums[2] == sums[3];
}
int element = nums[index];
for (int i = 0; i < 4; ++i) {
if (sums[i] + element <= possibleSquareSide) {
sums[i] += element;
if (dfs(index + 1)) {
return true;
}
sums[i] -= element;
}
}
return false;
}
bool makesquare(std::vector<int>& nums) {
if (nums.empty()) {
return false;
}
int perimeter = std::accumulate(nums.begin(), nums.end(), 0);
possibleSquareSide = perimeter / 4;
if (possibleSquareSide * 4 != perimeter) {
return false;
}
std::sort(nums.rbegin(), nums.rend());
this->nums = nums;
return dfs(0);
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 903. Valid Permutations for DI Sequence
Сложность: hard
Вам дана строка s длины n, где s[i] либо: 'D' означает убывание, либо 'I' означает возрастание. Перестановка perm из n + 1 целых чисел всех целых чисел в диапазоне [0, n] называется допустимой, если для всех допустимых i: если s[i] == 'D', то perm[i] > perm[i + 1], а если s[i] == 'I', то perm[i] < perm[i + 1]. Верните количество допустимых перестановок perm. Поскольку ответ может быть большим, верните его по модулю 109 + 7.
Пример:
Input: s = "DID" Output: 5👨💻 Алгоритм: 1⃣Создать двумерный массив dp, где dp[i][j] представляет количество допустимых перестановок длины i, оканчивающихся на j. 2⃣Заполнить массив dp, учитывая условия возрастания и убывания из строки s. 3⃣Вернуть сумму dp[n][j] для всех j, что даст количество допустимых перестановок длины n + 1. 😎 Решение:
class Solution {
public:
int numPermsDISequence(string s) {
const int MOD = 1e9 + 7;
int n = s.size();
vector<vector<int>> dp(n + 1, vector<int>(n + 1, 0));
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= i; j++) {
if (s[i - 1] == 'D') {
for (int k = j; k < i; k++) {
dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD;
}
} else {
for (int k = 0; k < j; k++) {
dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD;
}
}
}
}
int result = 0;
for (int j = 0; j <= n; j++) {
result = (result + dp[n][j]) % MOD;
}
return result;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 814. Binary Tree Pruning
Сложность: medium
Дан корень бинарного дерева. Верните то же дерево, в котором удалены все поддеревья (данного дерева), не содержащие 1.
Поддерево узла node - это сам узел node и все узлы, являющиеся потомками node.
Пример:
Input: root = [1,null,0,0,1] Output: [1,null,0,null,1] Explanation: Only the red nodes satisfy the property "every subtree not containing a 1". The diagram on the right represents the answer.👨💻 Алгоритм: 1⃣Используем функцию containsOne(node), которая сообщает, содержит ли поддерево в данном узле единицу, и обрезает все поддеревья, не содержащие единицу. 2⃣Например, если поддерево node.left не содержит единицу, то мы должны обрезать его через node.left = null. 3⃣Также нужно проверить родительский узел. Например, если дерево состоит из одного узла 0, то ответом будет пустое дерево. 😎 Решение:
class Solution {
public:
TreeNode* pruneTree(TreeNode* root) {
return containsOne(root) ? root : nullptr;
}
private:
bool containsOne(TreeNode* node) {
if (!node) return false;
bool leftContainsOne = containsOne(node->left);
bool rightContainsOne = containsOne(node->right);
if (!leftContainsOne) node->left = nullptr;
if (!rightContainsOne) node->right = nullptr;
return node->val == 1 || leftContainsOne || rightContainsOne;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 404. Sum of Left Leaves
Сложность: easy
Если задан корень бинарного дерева, верните сумму всех левых листьев. Лист - это узел, не имеющий детей. Левый лист - это лист, который является левым ребенком другого узла.
Пример:
Input: root = [3,9,20,null,null,15,7] Output: 24👨💻 Алгоритм: 1⃣Рекурсивный обход дерева Обходите дерево с помощью рекурсивной функции, которая принимает текущий узел и флаг, указывающий, является ли узел левым ребенком. 2⃣Проверка листьев Если текущий узел является листом и флаг указывает, что это левый ребенок, добавьте значение узла к сумме. 3⃣Рекурсивный вызов для детей Рекурсивно вызовите функцию для левого и правого детей текущего узла, передавая соответствующий флаг. 😎 Решение:
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
return dfs(root, false);
}
private:
int dfs(TreeNode* node, bool isLeft) {
if (!node) return 0;
if (!node->left && !node->right) return isLeft ? node->val : 0;
return dfs(node->left, true) + dfs(node->right, false);
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 336. Palindrome Pairs
Сложность: hard
Вам дан массив уникальных строк words, индексируемый с 0.
Пара палиндромов — это пара целых чисел (i, j), таких что:
0 <= i, j < words.length,
i != j, и
words[i] + words[j] (конкатенация двух строк) является палиндромом.
Верните массив всех пар палиндромов из слов.
Вы должны написать алгоритм с временной сложностью O(сумма длин всех слов в words).
Пример:
Input: words = ["abcd","dcba","lls","s","sssll"] Output: [[0,1],[1,0],[3,2],[2,4]] Explanation: The palindromes are ["abcddcba","dcbaabcd","slls","llssssll"]👨💻 Алгоритм: 1⃣Инициализация и подготовка данных: Создайте структуру для хранения результатов (список пар индексов). Создайте словарь для хранения слов и их индексов, чтобы ускорить поиск. 2⃣Итерация по всем парам слов и проверка: Пройдите по всем парам слов в массиве words, используя два вложенных цикла. Для каждой пары слов проверяйте, образуют ли они палиндром при конкатенации. Это делается путем объединения строк и проверки, равна ли объединенная строка своей обратной версии. 3⃣Добавление найденных пар в результат: Если проверка на палиндром проходит, добавьте текущую пару индексов в список результатов. Верните итоговый список всех найденных пар. 😎 Решение:
class Solution {
public:
vector<vector<int>> palindromePairs(vector<string>& words) {
vector<vector<int>> pairs;
for (int i = 0; i < words.size(); ++i) {
for (int j = 0; j < words.size(); ++j) {
if (i == j) continue;
string combined = words[i] + words[j];
string reversed = string(combined.rbegin(), combined.rend());
if (combined == reversed) {
pairs.push_back({i, j});
}
}
}
return pairs;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 1057. Campus Bikes
Сложность: medium
В городке, изображенном на плоскости X-Y, есть n рабочих и m велосипедов, причем n <= m. Вам дан массив workers длины n, где workers[i] = [xi, yi] - положение i-го рабочего. Вам также дан массив bikes длины m, где bikes[j] = [xj, yj] - позиция j-го велосипеда. Все заданные позиции уникальны. Назначаем велосипед каждому работнику. Среди доступных велосипедов и работников мы выбираем пару (workeri, bikej) с наименьшим манхэттенским расстоянием между ними и назначаем велосипед этому работнику. Если существует несколько пар (workeri, bikej) с одинаковым наименьшим манхэттенским расстоянием, мы выбираем пару с наименьшим индексом работника. Если существует несколько способов сделать это, мы выбираем пару с наименьшим индексом велосипеда. Повторяем этот процесс до тех пор, пока не останется свободных работников. Возвращаем массив answer длины n, где answer[i] - индекс (с индексом 0) велосипеда, на который назначен i-й работник. Манхэттенское расстояние между двумя точками p1 и p2 равно Manhattan(p1, p2) = |p1.x - p2.x| + |p1.y - p2.y|.
Пример:
Input: workers = [[0,0],[2,1]], bikes = [[1,2],[3,3]] Output: [1,0]👨💻 Алгоритм: 1⃣Для каждой пары (работник, велосипед) вычисли Манхэттенское расстояние и сохрани все пары вместе с расстоянием в список. 2⃣Отсортируй список пар по расстоянию, а затем по индексу работника и велосипеда. Назначь велосипеды работникам, следуя отсортированному списку пар и отслеживая, какие работники и велосипеды уже были использованы. 3⃣Заполни и верни массив назначений. 😎 Решение:
class Solution {
public:
vector<int> assignBikes(vector<vector<int>>& workers, vector<vector<int>>& bikes) {
vector<tuple<int, int, int>> pairs;
for (int i = 0; i < workers.size(); i++) {
for (int j = 0; j < bikes.size(); j++) {
int distance = abs(workers[i][0] - bikes[j][0]) + abs(workers[i][1] - bikes[j][1]);
pairs.emplace_back(distance, i, j);
}
}
sort(pairs.begin(), pairs.end());
vector<int> result(workers.size(), -1);
vector<bool> bikeTaken(bikes.size(), false);
vector<bool> workerAssigned(workers.size(), false);
for (auto& [distance, workerIdx, bikeIdx] : pairs) {
if (!workerAssigned[workerIdx] && !bikeTaken[bikeIdx]) {
result[workerIdx] = bikeIdx;
bikeTaken[bikeIdx] = true;
workerAssigned[workerIdx] = true;
}
}
return result;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 208. Implement Trie (Prefix Tree)
Сложность: medium
Реализуйте структуру данных Trie (префиксное дерево), поддерживающую следующие операции:
insert(word) — вставка слова
search(word) — проверка, было ли слово вставлено
startsWith(prefix) — проверка, начинается ли хоть одно вставленное слово с заданного префикса
Пример:
Input: ["Trie", "insert", "search", "search", "startsWith", "insert", "search"] [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]] Output: [null, null, true, false, true, null, true]👨💻 Алгоритм: 1⃣Инициализация и вставка: Каждый узел (TrieNode) содержит массив из 26 указателей (по одной на каждую букву алфавита) и флаг isEnd. Метод insert создает недостающие узлы и в конце устанавливает isEnd = true для последнего символа слова. 2⃣Поиск строки: Метод search использует вспомогательную функцию searchPrefix, которая проходит по всем символам слова. Если найденный узел существует и отмечен как конец слова, возвращаем true. 3⃣Проверка префикса: Метод startsWith использует searchPrefix, и возвращает true, если удалось дойти до конца заданного префикса. 😎 Решение:
#include <vector>
#include <string>
class TrieNode {
private:
TrieNode* links[26];
bool isEnd;
public:
TrieNode() : isEnd(false) {
for (int i = 0; i < 26; ++i) {
links[i] = nullptr;
}
}
bool containsKey(char ch) {
return links[ch - 'a'] != nullptr;
}
TrieNode* get(char ch) {
return links[ch - 'a'];
}
void put(char ch, TrieNode* node) {
links[ch - 'a'] = node;
}
void setEnd() {
isEnd = true;
}
bool isEndNode() {
return isEnd;
}
};
class Trie {
private:
TrieNode* root;
TrieNode* searchPrefix(const std::string& word) {
TrieNode* node = root;
for (char ch : word) {
if (node->containsKey(ch)) {
node = node->get(ch);
} else {
return nullptr;
}
}
return node;
}
public:
Trie() {
root = new TrieNode();
}
void insert(const std::string& word) {
TrieNode* node = root;
for (char ch : word) {
if (!node->containsKey(ch)) {
node->put(ch, new TrieNode());
}
node = node->get(ch);
}
node->setEnd();
}
bool search(const std::string& word) {
TrieNode* node = searchPrefix(word);
return node != nullptr && node->isEndNode();
}
bool startsWith(const std::string& prefix) {
return searchPrefix(prefix) != nullptr;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 1365. How Many Numbers Are Smaller Than the Current Number
Сложность: easy
Дан массив nums. Для каждого элемента nums[i] определите, сколько чисел в массиве меньше его. То есть, для каждого nums[i] вам нужно посчитать количество допустимых j, таких что j != i и nums[j] < nums[i].
Верните ответ в виде массива.
Пример:
Input: nums = [6,5,4,8] Output: [2,1,0,3]👨💻 Алгоритм: 1⃣Создание копии и сортировка массива: Создайте отсортированную копию массива nums, чтобы легко находить количество элементов, меньших текущего. 2⃣Поиск индекса каждого элемента: Для каждого элемента nums[i] найдите его индекс в отсортированной копии массива. Этот индекс указывает количество элементов, меньших nums[i]. 3⃣Формирование ответа: Сформируйте массив ответов, где каждый элемент будет соответствовать количеству чисел, меньших текущего. 😎 Решение:
#include <vector>
#include <algorithm>
class Solution {
public:
std::vector<int> smallerNumbersThanCurrent(std::vector<int>& nums) {
std::vector<int> sortedNums = nums;
std::sort(sortedNums.begin(), sortedNums.end());
std::vector<int> result;
for (int num : nums) {
result.push_back(std::find(sortedNums.begin(), sortedNums.end(), num) - sortedNums.begin());
}
return result;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 45. Jump Game II
Сложность: medium
Дан массив nums, где каждый элемент nums[i] обозначает максимальную длину прыжка из позиции i.
Необходимо вернуть минимальное количество прыжков, чтобы достичь последнего индекса.
Гарантируется, что это возможно.
Пример:
Input: nums = [2,3,0,1,4] Output: 2👨💻 Алгоритм: 1⃣Инициализировать: curEnd = 0 — граница текущего прыжка curFar = 0 — самая дальняя достижимая позиция answer = 0 — количество прыжков 2⃣Перебрать массив до предпоследнего индекса: На каждом шаге обновить curFar = max(curFar, i + nums[i]) 3⃣Когда текущий индекс достигает curEnd, совершается новый прыжок: Увеличить answer++ Обновить curEnd = curFar 😎 Решение:
class Solution {
public:
int jump(vector<int>& nums) {
int answer = 0, n = int(nums.size());
int curEnd = 0, curFar = 0;
for (int i = 0; i < n - 1; ++i) {
curFar = max(curFar, i + nums[i]);
if (i == curEnd) {
answer++;
curEnd = curFar;
}
}
return answer;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 1039. Minimum Score Triangulation of Polygon
Сложность: medium
У вас есть выпуклый n-сторонний многоугольник, каждая вершина которого имеет целочисленное значение. Вам дан целочисленный массив values, где values[i] - это значение i-й вершины (т.е. по часовой стрелке). Вы должны триангулировать многоугольник на n - 2 треугольника. Для каждого треугольника значение этого треугольника равно произведению значений его вершин, а общий балл триангуляции равен сумме этих значений для всех n - 2 треугольников в триангуляции. Верните наименьший возможный общий балл, который вы можете получить с помощью некоторой триангуляции многоугольника.
Пример:
Input: values = [1,2,3] Output: 6👨💻 Алгоритм: 1⃣Инициализация: Создаем двумерный массив dp, где dp[i][j] будет хранить минимальный возможный общий балл триангуляции многоугольника, состоящего из вершин от i до j. 2⃣Основное заполнение dp: Проходим по всем возможным длинам подмногоугольников, начиная с треугольников (длина 3) до всего многоугольника (длина n). Для каждого подмногоугольника находим минимальный возможный общий балл, проверяя все возможные треугольники, которые могут быть образованы из этого подмногоугольника. Заполнение dp для каждого подмногоугольника: Для каждого подмногоугольника от i до j, и для каждой возможной вершины k между i и j, обновляем значение dp[i][j], как сумму минимальных значений триангуляций левой и правой частей подмногоугольника, а также значения текущего треугольника, образованного вершинами i, k и j. 3⃣Возврат результата: Ответ будет в dp[0][n-1], который хранит минимальный возможный общий балл триангуляции для всего многоугольника. 😎 Решение:
class Solution {
public:
int minScoreTriangulation(vector<int>& values) {
int n = values.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
for (int length = 2; length < n; ++length) {
for (int i = 0; i < n - length; ++i) {
int j = i + length;
dp[i][j] = INT_MAX;
for (int k = i + 1; k < j; ++k) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + values[i] * values[j] * values[k]);
}
}
}
return dp[0][n - 1];
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 460. LFU Cache
Сложность: hard
Спроектируйте и реализуйте структуру данных для кеша с наименьшим количеством использования (Least Frequently Used, LFU).
Реализуйте класс LFUCache:
LFUCache(int capacity): Инициализирует объект с указанной вместимостью структуры данных.
int get(int key): Возвращает значение ключа, если ключ существует в кеше. В противном случае возвращает -1.
void put(int key, int value): Обновляет значение ключа, если он уже присутствует, или вставляет ключ, если его еще нет. Когда кеш достигает своей вместимости, он должен аннулировать и удалить ключ, используемый наименее часто, перед вставкой нового элемента. В этой задаче, если имеется несколько ключей с одинаковой частотой использования, аннулируется наименее недавно использованный ключ.
Чтобы определить наименее часто используемый ключ, для каждого ключа в кеше поддерживается счетчик использования. Ключ с наименьшим счетчиком использования является наименее часто используемым ключом.
Когда ключ впервые вставляется в кеш, его счетчик использования устанавливается на 1 (из-за операции put). Счетчик использования для ключа в кеше увеличивается при вызове операции get или put для этого ключа.
Функции get и put должны иметь среднюю временную сложность O(1).
Пример:
Input ["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]] Output [null, null, null, 1, null, -1, 3, null, -1, 3, 4]👨💻 Алгоритм: 1⃣insert(int key, int frequency, int value): Вставить пару частота-значение в cache с заданным ключом. Получить LinkedHashSet, соответствующий данной частоте (по умолчанию пустой Set), и вставить в него ключ. 2⃣int get(int key): Если ключа нет в кеше, вернуть -1. Получить частоту и значение из кеша. Удалить ключ из LinkedHashSet, связанного с частотой. Если minf == frequency и LinkedHashSet пуст, увеличить minf на 1 и удалить запись частоты из frequencies. Вызвать insert(key, frequency + 1, value). Вернуть значение. 3⃣void put(int key, int value): Если capacity <= 0, выйти. Если ключ существует, обновить значение и вызвать get(key). Если размер кеша равен capacity, удалить первый элемент из LinkedHashSet, связанного с minf, и из кеша. Установить minf в 1. Вызвать insert(key, 1, value). 😎 Решение:
#include <unordered_map>
#include <list>
class LFUCache {
std::unordered_map<int, std::list<std::pair<int, int>>> frequencies;
std::unordered_map<int, std::pair<int, std::list<std::pair<int, int>>::iterator>> cache;
int capacity;
int minf;
void insert(int key, int frequency, int value) {
frequencies[frequency].emplace_back(key, value);
cache[key] = {frequency, --frequencies[frequency].end()};
}
public:
LFUCache(int capacity) : capacity(capacity), minf(0) {}
int get(int key) {
const auto it = cache.find(key);
if (it == cache.end()) return -1;
const int f = it->second.first;
const auto iter = it->second.second;
const std::pair<int, int> kv = *iter;
frequencies[f].erase(iter);
if (frequencies[f].empty()) {
frequencies.erase(f);
if (minf == f) ++minf;
}
insert(key, f + 1, kv.second);
return kv.second;
}
void put(int key, int value) {
if (capacity <= 0) return;
const auto it = cache.find(key);
if (it != cache.end()) {
it->second.second->second = value;
get(key);
return;
}
if (capacity == cache.size()) {
cache.erase(frequencies[minf].front().first);
frequencies[minf].pop_front();
if (frequencies[minf].empty()) frequencies.erase(minf);
}
minf = 1;
insert(key, 1, value);
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 69. Sqrt(x)
Сложность: easy
Дано неотрицательное число x. Верните его целочисленный квадратный корень, округлённый вниз.
Нельзя использовать встроенные функции, вроде pow или sqrt.
Пример:
Input: x = 4 Output: 2👨💻 Алгоритм: 1⃣Если x < 2, сразу вернуть x, так как sqrt(0) = 0, sqrt(1) = 1 2⃣Используем бинарный поиск в диапазоне от 2 до x / 2 На каждой итерации: pivot = (left + right) / 2 Если pivot * pivot == x, вернуть pivot Если pivot * pivot < x, сдвинуть left = pivot + 1 Иначе right = pivot - 1 3⃣В конце вернуть right, т.к. он будет ближайшим целым значением, квадрат которого ≤ x 😎 Решение:
class Solution {
public:
int mySqrt(int x) {
if (x < 2) return x;
long num;
int pivot, left = 2, right = x / 2;
while (left <= right) {
pivot = left + (right - left) / 2;
num = (long)pivot * pivot;
if (num > x)
right = pivot - 1;
else if (num < x)
left = pivot + 1;
else
return pivot;
}
return right;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 1047. Remove All Adjacent Duplicates In String
Сложность: easy
Вам дана строка s, состоящая из строчных английских букв. Удаление дубликатов заключается в выборе двух соседних и одинаковых букв и их удалении. Мы многократно производим удаление дубликатов в s, пока не перестанем это делать. Верните конечную строку после того, как все такие удаления дубликатов будут произведены. Можно доказать, что ответ уникален.
Пример:
Input: stones = [2,7,4,1,8,1] Output: 1👨💻 Алгоритм: 1⃣Создай пустой стек для хранения символов строки. 2⃣Проходи по символам строки, добавляя каждый символ в стек, если он не совпадает с верхним элементом стека, иначе удаляй верхний элемент. 3⃣После прохождения по строке, собери оставшиеся символы в стеке в результирующую строку и верни ее. 😎 Решение:
class Solution {
public:
string removeDuplicates(string s) {
stack<char> stack;
for (char c : s) {
if (!stack.empty() && stack.top() == c) {
stack.pop();
} else {
stack.push(c);
}
}
string result;
while (!stack.empty()) {
result += stack.top();
stack.pop();
}
reverse(result.begin(), result.end());
return result;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 1426. Counting Elements
Сложность: easy
Дан целочисленный массив arr, посчитайте, сколько элементов x в нем есть таких, что x + 1 также находится в arr. Если в arr есть дубликаты, считайте их отдельно.
Пример:
Input: arr = [1,2,3] Output: 2 Explanation: 1 and 2 are counted cause 2 and 3 are in arr.👨💻 Алгоритм: 1⃣Создайте вспомогательную функцию для проверки, содержится ли элемент в массиве. 2⃣Итерируйте по каждому элементу массива и используйте вспомогательную функцию для проверки, содержится ли элемент x + 1 в массиве. 3⃣Увеличьте счетчик, если x + 1 найден, и верните значение счетчика. 😎 Решение:
class Solution {
public:
int countElements(vector<int>& arr) {
int count = 0;
for (int x : arr) {
if (integerInArray(arr, x + 1)) {
count++;
}
}
return count;
}
bool integerInArray(vector<int>& arr, int target) {
for (int x : arr) {
if (x == target) {
return true;
}
}
return false;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 895. Maximum Frequency Stack
Сложность: hard
Разработайте структуру данных, похожую на стек, чтобы заталкивать элементы в стек и вытаскивать из него самый частый элемент. Реализуйте класс FreqStack: FreqStack() строит пустой стек частот. void push(int val) заталкивает целое число val на вершину стека. int pop() удаляет и возвращает самый частый элемент в стеке. Если есть равенство в выборе самого частого элемента, то удаляется и возвращается элемент, который ближе всего к вершине стека.
Пример:
Input ["FreqStack", "push", "push", "push", "push", "push", "push", "pop", "pop", "pop", "pop"] [[], [5], [7], [5], [7], [4], [5], [], [], [], []] Output [null, null, null, null, null, null, null, 5, 7, 5, 4]👨💻 Алгоритм: 1⃣Создать два словаря: freq для хранения частоты каждого элемента и group для хранения стека элементов для каждой частоты. 2⃣При добавлении элемента увеличивать его частоту в freq и добавлять его в стек соответствующей частоты в group. 3⃣При извлечении элемента найти максимальную частоту, удалить элемент из стека соответствующей частоты и уменьшить его частоту в freq. Если стек для данной частоты становится пустым, удалить его. 😎 Решение:
class FreqStack {
std::unordered_map<int, int> freq;
std::unordered_map<int, std::stack<int>> group;
int maxfreq = 0;
public:
FreqStack() {}
void push(int val) {
int f = ++freq[val];
if (f > maxfreq) maxfreq = f;
group[f].push(val);
}
int pop() {
int val = group[maxfreq].top();
group[maxfreq].pop();
if (group[maxfreq].empty()) maxfreq--;
freq[val]--;
return val;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 1196. How Many Apples Can You Put into the Basket
Сложность: easy
У вас есть несколько яблок и корзина, которая может выдержать до 5000 единиц веса.
Дан целочисленный массив weight, где weight[i] — это вес i-го яблока. Верните максимальное количество яблок, которые можно положить в корзину.
Пример:
Input: weight = [100,200,150,1000] Output: 4 Explanation: All 4 apples can be carried by the basket since their sum of weights is 1450.👨💻 Алгоритм: 1⃣Преобразование массива в мин-кучу: Преобразуйте массив weight в мин-кучу, чтобы получить минимальные элементы первым. 2⃣Инициализация переменных: Инициализируйте переменные apples для подсчета количества яблок и units для записи текущего веса корзины. 3⃣Добавление яблок в корзину: Пока текущий вес корзины меньше 5000 единиц и в куче остаются элементы: Увеличивайте apples на 1. Увеличивайте units на значение, извлеченное из кучи. 😎 Решение:
class Solution {
public:
int maxNumberOfApples(vector<int>& weight) {
priority_queue<int, vector<int>, greater<int>> heap(weight.begin(), weight.end());
int apples = 0, units = 0;
while (!heap.empty() && units + heap.top() <= 5000) {
units += heap.top();
heap.pop();
apples++;
}
return apples;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 1219. Path with Maximum Gold
Сложность: medium
В золотом руднике размером m x n каждая ячейка содержит целое число, представляющее количество золота в этой ячейке, или 0, если она пуста.
Верните максимальное количество золота, которое вы можете собрать при следующих условиях:
- Каждый раз, когда вы находитесь в ячейке, вы собираете всё золото из этой ячейки.
- Из вашей позиции вы можете сделать один шаг влево, вправо, вверх или вниз.
- Вы не можете посещать одну и ту же ячейку более одного раза.
- Никогда не посещайте ячейку с 0 золотом.
- Вы можете начинать и прекращать сбор золота с любой позиции в сетке, которая содержит золото.
Пример:
Input: grid = [[0,6,0],[5,8,7],[0,9,0]] Output: 24 Explanation: [[0,6,0], [5,8,7], [0,9,0]] Path to get the maximum gold, 9 -> 8 -> 7.👨💻 Алгоритм: 1⃣Инициализация и подготовка: Инициализируйте константный массив DIRECTIONS для направления перемещений. Определите количество строк и столбцов в сетке. Инициализируйте переменную maxGold для хранения максимального количества собранного золота. 2⃣Функция DFS и обратный трек: Реализуйте функцию dfsBacktrack для поиска пути с максимальным золотом с помощью DFS и обратного трека. Обрабатывайте базовый случай, проверяя выход за пределы сетки или ячейки без золота. Пометьте текущую ячейку как посещённую и сохраните её значение. Исследуйте каждую из четырёх смежных ячеек и обновите максимальное количество золота, если найден лучший путь. Сбросьте текущую ячейку до её исходного значения для дальнейших исследований. 3⃣Поиск максимального золота: Используйте вложенные циклы для каждой ячейки в сетке, чтобы найти максимальное количество золота, начиная с этой ячейки, с помощью функции dfsBacktrack. Обновите maxGold при нахождении лучшего пути. Верните maxGold. 😎 Решение:
class Solution {
public:
int getMaximumGold(vector<vector<int>>& grid) {
int rows = grid.size(), cols = grid[0].size(), maxGold = 0;
for (int row = 0; row < rows; ++row) {
for (int col = 0; col < cols; ++col) {
maxGold = max(maxGold, dfsBacktrack(grid, rows, cols, row, col));
}
}
return maxGold;
}
private:
int directions[5] = {0, 1, 0, -1, 0};
int dfsBacktrack(vector<vector<int>>& grid, int rows, int cols, int row, int col) {
if (row < 0 || col < 0 || row >= rows || col >= cols || grid[row][col] == 0) return 0;
int originalVal = grid[row][col];
grid[row][col] = 0;
int maxGold = 0;
for (int i = 0; i < 4; ++i) {
maxGold = max(maxGold, dfsBacktrack(grid, rows, cols, row + directions[i], col + directions[i + 1]));
}
grid[row][col] = originalVal;
return maxGold + originalVal;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 468. Validate IP Address
Сложность: medium
Допустимый IPv4-адрес — это IP в форме "x1.x2.x3.x4", где 0 <= xi <= 255 и xi не может содержать ведущие нули. Например, "192.168.1.1" и "192.168.1.0" являются допустимыми IPv4-адресами, тогда как "192.168.01.1", "192.168.1.00" и "192.168@1.1" являются недопустимыми IPv4-адресами.
Допустимый IPv6-адрес — это IP в форме "x1:x2:x3:x4:x5:x6:x7
", где:
1 <= xi.length <= 4
xi — это шестнадцатеричная строка, которая может содержать цифры, строчные английские буквы ('a' до 'f') и прописные английские буквы ('A' до 'F').
Ведущие нули в xi допускаются.
Пример:
Input: queryIP = "172.16.254.1"
Output: "IPv4"
Explanation: This is a valid IPv4 address, return "IPv4".
👨💻 Алгоритм:
1⃣Для проверки адреса IPv4:
Разделить IP на четыре части по разделителю ".".
Проверить каждую подстроку:
Является ли она целым числом между 0 и 255.
Не содержит ли она ведущих нулей (исключение — число "0").
2⃣Для проверки адреса IPv6:
Разделить IP на восемь частей по разделителю ":".
Проверить каждую подстроку:
Является ли она шестнадцатеричным числом длиной от 1 до 4 символов.
3⃣Если IP не соответствует ни одному из форматов, вернуть "Neither".
😎 Решение:
class Solution {
public:
std::string validateIPv4(const std::string& IP) {
std::vector<std::string> nums = split(IP, '.');
if (nums.size() != 4) return "Neither";
for (std::string& x : nums) {
if (x.size() == 0 || x.size() > 3) return "Neither";
if (x[0] == '0' && x.size() != 1) return "Neither";
if (!std::all_of(x.begin(), x.end(), ::isdigit)) return "Neither";
if (std::stoi(x) > 255) return "Neither";
}
return "IPv4";
}
std::string validateIPv6(const std::string& IP) {
std::vector<std::string> nums = split(IP, ':');
if (nums.size() != 8) return "Neither";
std::unordered_set<char> hexdigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'};
for (std::string& x : nums) {
if (x.size() == 0 || x.size() > 4) return "Neither";
for (char ch : x) {
if (hexdigits.find(ch) == hexdigits.end()) return "Neither";
}
}
return "IPv6";
}
std::string validIPAddress(const std::string& IP) {
if (std::count(IP.begin(), IP.end(), '.') == 3) {
return validateIPv4(IP);
} else if (std::count(IP.begin(), IP.end(), ':') == 7) {
return validateIPv6(IP);
} else {
return "Neither";
}
}
private:
std::vector<std::string> split(const std::string& s, char delimiter) {
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(s);
while (std::getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 259
Задача: 360. Sort Transformed Array
Сложность: medium
Дан отсортированный массив целых чисел nums и три целых числа a, b и c. Примените квадратичную функцию вида f(x) = ax^2 + bx + c к каждому элементу nums[i] в массиве и верните массив в отсортированном порядке.
Пример:
Input: nums = [-4,-2,2,4], a = 1, b = 3, c = 5
Output: [3,9,15,33]
👨💻 Алгоритм:
1⃣Преобразование и сортировка
Преобразуем каждый элемент массива nums по квадратичной функции f(x) = ax^2 + bx + c и сохраняем результаты в массив transformed. Используем алгоритм поразрядной сортировки для сортировки массива transformed.
2⃣Поразрядная сортировка
Находим максимальное значение по модулю в массиве для определения количества цифр. Применяем поразрядную сортировку к массиву transformed.
3⃣Сортировка по цифре
Для каждой цифры (разряда) используем подсчет для сортировки массива.
😎 Решение:
#include <vector>
#include <algorithm>
#include <cmath>
class Solution {
public:
std::vector<int> sortTransformedArray(std::vector<int>& nums, int a, int b, int c) {
std::vector<int> transformed(nums.size());
for (size_t i = 0; i < nums.size(); ++i) {
transformed[i] = a * nums[i] * nums[i] + b * nums[i] + c;
}
radixSort(transformed);
return transformed;
}
private:
void radixSort(std::vector<int>& array) {
int maxElement = abs(array[0]);
for (int num : array) {
maxElement = std::max(maxElement, abs(num));
}
for (int placeValue = 1; maxElement / placeValue > 0; placeValue *= 10) {
countingSortByDigit(array, placeValue);
}
std::vector<int> negatives, positives;
for (int num : array) {
if (num < 0) negatives.push_back(num);
else positives.push_back(num);
}
std::sort(negatives.begin(), negatives.end());
std::sort(positives.begin(), positives.end());
std::merge(negatives.begin(), negatives.end(), positives.begin(), positives.end(), array.begin());
}
void countingSortByDigit(std::vector<int>& array, int placeValue) {
std::vector<int> output(array.size());
std::vector<int> count(10, 0);
for (int num : array) {
int digit = (abs(num) / placeValue) % 10;
count[digit]++;
}
for (int i = 1; i < 10; ++i) {
count[i] += count[i - 1];
}
for (int i = array.size() - 1; i >= 0; --i) {
int num = array[i];
int digit = (abs(num) / placeValue) % 10;
output[count[digit] - 1] = num;
count[digit]--;
}
for (size_t i = 0; i < array.size(); ++i) {
array[i] = output[i];
}
}
};
Ставь 👍 и забирай 📚 Базу знаний
Вже доступно! Дослідження Telegram за 2025 — головні інсайти року 
