Задача: 122. Best Time to Buy and Sell Stock II
Сложность: medium
Вам дан массив целых чисел prices, где prices[i] — это цена акции в i-й день.
Каждый день вы можете купить и/или продать акцию, но держать в руках можно только одну. Разрешено покупать и продавать в тот же день.
Найдите и верните максимальную прибыль, которую можно получить.
Пример:
👨💻 Алгоритм:
1⃣ Найдём все возрастающие отрезки (впадина → пик), и прибавим к прибыли разницу между пиком и впадиной.
2⃣ Не стоит пытаться найти один глобальный минимум и максимум — это уменьшит прибыль. Лучше учитывать все локальные сделки, даже если они малы.
3⃣ Реализуем проход по массиву:
Ищем впадину (где цена начинает расти)
Затем ищем пик (где рост заканчивается)
Добавляем разницу в maxprofit
Повторяем до конца
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан массив целых чисел prices, где prices[i] — это цена акции в i-й день.
Каждый день вы можете купить и/или продать акцию, но держать в руках можно только одну. Разрешено покупать и продавать в тот же день.
Найдите и верните максимальную прибыль, которую можно получить.
Пример:
Input: prices = [7,1,5,3,6,4] Output: 7
Explanation:
Купить на 2-й день (цена = 1), продать на 3-й (цена = 5), прибыль = 4
Купить на 4-й день (цена = 3), продать на 5-й (цена = 6), прибыль = 3
Итоговая прибыль = 4 + 3 = 7
Ищем впадину (где цена начинает расти)
Затем ищем пик (где рост заканчивается)
Добавляем разницу в maxprofit
Повторяем до конца
class Solution {
public:
int maxProfit(vector<int>& prices) {
int i = 0;
int valley = prices[0];
int peak = prices[0];
int maxprofit = 0;
while (i < prices.size() - 1) {
while (i < prices.size() - 1 && prices[i] >= prices[i + 1]) i++;
valley = prices[i];
while (i < prices.size() - 1 && prices[i] <= prices[i + 1]) i++;
peak = prices[i];
maxprofit += peak - valley;
}
return maxprofit;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1510. Stone Game IV
Сложность: hard
Алиса и Боб поочередно играют в игру, причем Алиса начинает первой.
Изначально в куче n камней. В ходе каждого хода игрок удаляет любое ненулевое количество камней, являющееся квадратом целого числа.
Кроме того, если игрок не может сделать ход, он/она проигрывает игру.
Дано положительное целое число n, верните true, если и только если Алиса выиграет игру, иначе верните false, предполагая, что оба игрока играют оптимально.
Пример:
👨💻 Алгоритм:
1⃣ Функция dfs(remain) представляет собой проверку, должен ли текущий игрок выиграть при оставшихся remain камнях.
2⃣ Для определения результата dfs(n) необходимо итерировать k от 0, чтобы проверить, существует ли такое k, что dfs(remain - k*k) == False. Чтобы предотвратить избыточные вычисления, используйте карту для хранения результатов функции dfs.
3⃣ Не забудьте базовые случаи: dfs(0) == False и dfs(1) == True.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Алиса и Боб поочередно играют в игру, причем Алиса начинает первой.
Изначально в куче n камней. В ходе каждого хода игрок удаляет любое ненулевое количество камней, являющееся квадратом целого числа.
Кроме того, если игрок не может сделать ход, он/она проигрывает игру.
Дано положительное целое число n, верните true, если и только если Алиса выиграет игру, иначе верните false, предполагая, что оба игрока играют оптимально.
Пример:
Input: n = 1
Output: true
Explanation: Alice can remove 1 stone winning the game because Bob doesn't have any moves.
class Solution {
public:
bool winnerSquareGame(int n) {
unordered_map<int, bool> cache;
cache[0] = false;
return dfs(cache, n);
}
bool dfs(unordered_map<int, bool>& cache, int remain) {
if (cache.find(remain) != cache.end()) {
return cache[remain];
}
int sqrt_root = (int) sqrt(remain);
for (int i = 1; i <= sqrt_root; ++i) {
if (!dfs(cache, remain - i * i)) {
cache[remain] = true;
return true;
}
}
cache[remain] = false;
return false;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1024. Video Stitching
Сложность: medium
Вам дана серия видеоклипов со спортивного соревнования, длительность которых составляет несколько секунд. Эти видеоклипы могут накладываться друг на друга и иметь различную длину. Каждый видеоклип описывается массивом clips, где clips[i] = [starti, endi] указывает, что i-й клип начинается в starti и заканчивается в endi. Мы можем произвольно разрезать эти клипы на сегменты. Например, клип [0, 7] может быть разрезан на сегменты [0, 1] + [1, 3] + [3, 7]. Верните минимальное количество клипов, необходимое для того, чтобы мы могли разрезать клипы на сегменты, охватывающие все спортивное событие [0, время]. Если задача невыполнима, верните -1.
Пример:
👨💻 Алгоритм:
1⃣ Сортировка клипов:
Отсортируйте клипы по начальным значениям. Если начальные значения равны, отсортируйте по конечным значениям в убывающем порядке.
2⃣ Выбор клипов:
Используйте жадный алгоритм для выбора клипов. Начните с начальной точки 0 и двигайтесь вперед, выбирая клип, который может покрыть наибольший диапазон.
Если обнаруживается, что начальная точка текущего клипа больше текущей позиции, это означает, что клипы не могут покрыть промежуток, и нужно вернуть -1.
3⃣ Проверка покрытия:
Продолжайте процесс, пока не покроете весь диапазон от 0 до T. Если в конце процесса достигнута или превышена точка T, верните количество использованных клипов, иначе верните -1.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дана серия видеоклипов со спортивного соревнования, длительность которых составляет несколько секунд. Эти видеоклипы могут накладываться друг на друга и иметь различную длину. Каждый видеоклип описывается массивом clips, где clips[i] = [starti, endi] указывает, что i-й клип начинается в starti и заканчивается в endi. Мы можем произвольно разрезать эти клипы на сегменты. Например, клип [0, 7] может быть разрезан на сегменты [0, 1] + [1, 3] + [3, 7]. Верните минимальное количество клипов, необходимое для того, чтобы мы могли разрезать клипы на сегменты, охватывающие все спортивное событие [0, время]. Если задача невыполнима, верните -1.
Пример:
Input: clips = [[0,2],[4,6],[8,10],[1,9],[1,5],[5,9]], time = 10
Output: 3
Отсортируйте клипы по начальным значениям. Если начальные значения равны, отсортируйте по конечным значениям в убывающем порядке.
Используйте жадный алгоритм для выбора клипов. Начните с начальной точки 0 и двигайтесь вперед, выбирая клип, который может покрыть наибольший диапазон.
Если обнаруживается, что начальная точка текущего клипа больше текущей позиции, это означает, что клипы не могут покрыть промежуток, и нужно вернуть -1.
Продолжайте процесс, пока не покроете весь диапазон от 0 до T. Если в конце процесса достигнута или превышена точка T, верните количество использованных клипов, иначе верните -1.
class Solution {
public:
int videoStitching(vector<vector<int>>& clips, int T) {
sort(clips.begin(), clips.end(), [](const vector<int>& a, const vector<int>& b) {
return a[0] < b[0] || (a[0] == b[0] && a[1] > b[1]);
});
int end = -1, end2 = 0, res = 0;
for (const auto& clip : clips) {
if (end2 >= T || clip[0] > end2) break;
if (end < clip[0] && clip[0] <= end2) {
res++;
end = end2;
}
end2 = max(end2, clip[1]);
}
return end2 >= T ? res : -1;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 974. Subarray Sums Divisible by K
Сложность: medium
Дан целочисленный массив nums и целое число k. Верните количество непустых подмассивов, сумма которых делится на k.
Подмассив — это непрерывная часть массива.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и подготовка. Инициализируйте prefixMod = 0 для хранения остатка от суммы элементов до текущего индекса при делении на k. Инициализируйте result = 0 для хранения количества подмассивов, сумма которых делится на k. Инициализируйте массив modGroups длиной k, где modGroups[R] хранит количество подмассивов с остатком R. Установите modGroups[0] = 1.
2⃣ Итерирование по массиву. Для каждого элемента массива nums вычислите новый prefixMod как (prefixMod + nums[i] % k + k) % k, чтобы избежать отрицательных значений. Увеличьте result на значение modGroups[prefixMod], чтобы добавить количество подмассивов с текущим остатком. Увеличьте значение modGroups[prefixMod] на 1 для будущих совпадений.
3⃣ Возврат результата. Верните значение result, которое содержит количество подмассивов, сумма которых делится на k.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан целочисленный массив nums и целое число k. Верните количество непустых подмассивов, сумма которых делится на k.
Подмассив — это непрерывная часть массива.
Пример:
Input: nums = [4,5,0,-2,-3,1], k = 5
Output: 7
Explanation: There are 7 subarrays with a sum divisible by k = 5:
[4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]
class Solution {
public:
int subarraysDivByK(vector<int>& nums, int k) {
int prefixMod = 0, result = 0;
vector<int> modGroups(k);
modGroups[0] = 1;
for (int num : nums) {
prefixMod = (prefixMod + num % k + k) % k;
result += modGroups[prefixMod];
modGroups[prefixMod]++;
}
return result;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 918. Maximum Sum Circular Subarray
Сложность: medium
Если задан круговой целочисленный массив nums длины n, верните максимально возможную сумму непустого подмассива nums. Круговой массив означает, что конец массива соединяется с его началом. Формально, следующий элемент nums[i] равен nums[(i + 1) % n], а предыдущий элемент nums[i] равен nums[(i - 1 + n) % n]. Подмассив может включать каждый элемент фиксированного буфера nums не более одного раза. Формально, для подмассива nums[i], nums[i + 1], ..., nums[j] не существует i <= k1, k2 <= j, при этом k1 % n == k2 % n.
Пример:
👨💻 Алгоритм:
1⃣ Найти стандартную максимальную сумму подмассива с помощью алгоритма Кадане.
2⃣ Найти минимальную сумму подмассива с помощью алгоритма Кадане и вычесть ее из общей суммы массива.
3⃣ Вернуть максимум между стандартной максимальной суммой подмассива и общей суммой массива минус минимальную сумму подмассива, если результат не равен 0 (чтобы учесть случай, когда все числа отрицательные).
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Если задан круговой целочисленный массив nums длины n, верните максимально возможную сумму непустого подмассива nums. Круговой массив означает, что конец массива соединяется с его началом. Формально, следующий элемент nums[i] равен nums[(i + 1) % n], а предыдущий элемент nums[i] равен nums[(i - 1 + n) % n]. Подмассив может включать каждый элемент фиксированного буфера nums не более одного раза. Формально, для подмассива nums[i], nums[i + 1], ..., nums[j] не существует i <= k1, k2 <= j, при этом k1 % n == k2 % n.
Пример:
Input: nums = [1,-2,3,-2]
Output: 3
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
int kadane(vector<int>& arr) {
int currentSum = arr[0], maxSum = arr[0];
for (int i = 1; i < arr.size(); ++i) {
currentSum = max(arr[i], currentSum + arr[i]);
maxSum = max(maxSum, currentSum);
}
return maxSum;
}
int maxKadane = kadane(nums);
int totalSum = accumulate(nums.begin(), nums.end(), 0);
for (int& num : nums) num = -num;
int minKadane = kadane(nums);
return max(maxKadane, totalSum + minKadane == 0 ? maxKadane : totalSum + minKadane);
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
Задача: 1302. Deepest Leaves Sum
Сложность: medium
Дано корень бинарного дерева, вернуть сумму значений его самых глубоких листьев.
Пример:
👨💻 Алгоритм:
1⃣ Поместите корень в стек.
2⃣ Пока стек не пуст. Извлеките узел из стека и обновите текущее число. Если узел является листом, обновите сумму самых глубоких листьев deepest_sum. Поместите правый и левый дочерние узлы в стек.
3⃣ Верните deepest_sum.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дано корень бинарного дерева, вернуть сумму значений его самых глубоких листьев.
Пример:
Input: root = [1,2,3,4,5,null,6,7,null,null,null,null,8]
Output: 15
class Solution {
public:
int deepestLeavesSum(TreeNode* root) {
int deepestSum = 0, depth = 0, currDepth;
stack<pair<TreeNode*, int>> stack;
stack.push({root, 0});
while (!stack.empty()) {
auto [node, currDepth] = stack.top();
stack.pop();
if (!node->left && !node->right) {
if (depth < currDepth) {
deepestSum = node->val;
depth = currDepth;
} else if (depth == currDepth) {
deepestSum += node->val;
}
} else {
if (node->right) {
stack.push({node->right, currDepth + 1});
}
if (node->left) {
stack.push({node->left, currDepth + 1});
}
}
}
return deepestSum;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 345. Reverse Vowels of a String
Сложность: easy
Дана строка s, переверните только все гласные в строке и верните её.
Гласные: 'a', 'e', 'i', 'o', 'u', а также их верхние регистры.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация указателей и гласных:
Создайте набор гласных для быстрой проверки.
Установите два указателя: один на начало строки (left), другой на конец строки (right).
2⃣ Перестановка гласных:
Пока левый указатель меньше правого, перемещайте указатели к центру, пока не найдёте гласные.
Обменивайте найденные гласные и продолжайте сдвигать указатели.
3⃣ Завершение работы:
Когда указатели пересекутся, остановите процесс и верните строку.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дана строка s, переверните только все гласные в строке и верните её.
Гласные: 'a', 'e', 'i', 'o', 'u', а также их верхние регистры.
Пример:
Input: s = "hello"
Output: "holle"
Создайте набор гласных для быстрой проверки.
Установите два указателя: один на начало строки (left), другой на конец строки (right).
Пока левый указатель меньше правого, перемещайте указатели к центру, пока не найдёте гласные.
Обменивайте найденные гласные и продолжайте сдвигать указатели.
Когда указатели пересекутся, остановите процесс и верните строку.
class Solution {
public:
string reverseVowels(string s) {
unordered_set<char> vowels = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'};
int left = 0, right = s.size() - 1;
while (left < right) {
if (vowels.find(s[left]) == vowels.end()) {
left++;
} else if (vowels.find(s[right]) == vowels.end()) {
right--;
} else {
swap(s[left], s[right]);
left++;
right--;
}
}
return s;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1248. Count Number of Nice Subarrays
Сложность: medium
Вам даны две строки s1 и s2 одинаковой длины, состоящие только из букв "x" и "y". Ваша задача - сделать эти две строки равными друг другу. Вы можете поменять местами любые два символа, принадлежащие разным строкам, что означает: поменять местами s1[i] и s2[j]. Верните минимальное количество обменов, необходимое для того, чтобы сделать s1 и s2 равными, или верните -1, если это невозможно сделать.
Пример:
👨💻 Алгоритм:
1⃣ Преобразуйте массив чисел nums, заменив все чётные числа на 0, а все нечётные числа на 1.
2⃣ Используя технику скользящего окна (или двух указателей), найдите все подмассивы, содержащие ровно k единиц.
3⃣ Подсчитайте количество таких подмассивов и верните этот результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам даны две строки s1 и s2 одинаковой длины, состоящие только из букв "x" и "y". Ваша задача - сделать эти две строки равными друг другу. Вы можете поменять местами любые два символа, принадлежащие разным строкам, что означает: поменять местами s1[i] и s2[j]. Верните минимальное количество обменов, необходимое для того, чтобы сделать s1 и s2 равными, или верните -1, если это невозможно сделать.
Пример:
Input: arr = [1,2]
Output: 2
class Solution {
public:
int numberOfSubarrays(vector<int>& nums, int k) {
return atMost(nums, k) - atMost(nums, k - 1);
}
private:
int atMost(vector<int>& nums, int k) {
int res = 0, left = 0, count = 0;
for (int right = 0; right < nums.size(); right++) {
if (nums[right] % 2 == 1) count++;
while (count > k) {
if (nums[left++] % 2 == 1) count--;
}
res += right - left + 1;
}
return res;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊1
Задача: 329. Longest Increasing Path in a Matrix
Сложность: hard
Дана матрица целых чисел размером m x n. Верните длину самого длинного возрастающего пути в матрице.
Из каждой ячейки можно перемещаться в четырех направлениях: влево, вправо, вверх или вниз. Перемещение по диагонали или выход за границы матрицы (т.е. замкнутые переходы) не допускается.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и создание матрицы:
Инициализируйте размеры матрицы m и n. Создайте матрицу matrix с добавленными границами (нулевыми значениями) вокруг исходной матрицы, чтобы избежать выхода за пределы при обработке.
Рассчитайте количество исходящих связей (outdegrees) для каждой клетки и сохраните их в outdegree.
2⃣ Поиск начальных листьев:
Найдите все клетки с нулевыми исходящими связями и добавьте их в список leaves. Эти клетки будут начальной точкой для "слоевого удаления".
3⃣ Удаление слоев:
Повторяйте процесс удаления клеток уровня за уровнем в порядке топологической сортировки, пока не останется листьев. Обновляйте количество исходящих связей и добавляйте новые листья на следующем уровне. Подсчитывайте количество уровней, что в итоге даст длину самого длинного возрастающего пути.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дана матрица целых чисел размером m x n. Верните длину самого длинного возрастающего пути в матрице.
Из каждой ячейки можно перемещаться в четырех направлениях: влево, вправо, вверх или вниз. Перемещение по диагонали или выход за границы матрицы (т.е. замкнутые переходы) не допускается.
Пример:
Input: matrix = [[9,9,4],[6,6,8],[2,1,1]]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9].
Инициализируйте размеры матрицы m и n. Создайте матрицу matrix с добавленными границами (нулевыми значениями) вокруг исходной матрицы, чтобы избежать выхода за пределы при обработке.
Рассчитайте количество исходящих связей (outdegrees) для каждой клетки и сохраните их в outdegree.
Найдите все клетки с нулевыми исходящими связями и добавьте их в список leaves. Эти клетки будут начальной точкой для "слоевого удаления".
Повторяйте процесс удаления клеток уровня за уровнем в порядке топологической сортировки, пока не останется листьев. Обновляйте количество исходящих связей и добавляйте новые листья на следующем уровне. Подсчитывайте количество уровней, что в итоге даст длину самого длинного возрастающего пути.
class Solution {
private:
static constexpr int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public:
int longestIncreasingPath(vector<vector<int>>& grid) {
int m = grid.size();
if (m == 0) return 0;
int n = grid[0].size();
vector<vector<int>> matrix(m + 2, vector<int>(n + 2));
vector<vector<int>> outdegree(m + 2, vector<int>(n + 2));
for (int i = 0; i < m; ++i) {
copy(grid[i].begin(), grid[i].end(), matrix[i + 1].begin() + 1);
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
for (auto& d : dir) {
if (matrix[i][j] < matrix[i + d[0]][j + d[1]]) {
outdegree[i][j]++;
}
}
}
}
vector<pair<int, int>> leaves;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (outdegree[i][j] == 0) leaves.emplace_back(i, j);
}
}
int height = 0;
while (!leaves.empty()) {
++height;
vector<pair<int, int>> newLeaves;
for (auto& node : leaves) {
for (auto& d : dir) {
int x = node.first + d[0], y = node.second + d[1];
if (matrix[node.first][node.second] > matrix[x][y]) {
if (--outdegree[x][y] == 0) {
newLeaves.emplace_back(x, y);
}
}
}
}
leaves.swap(newLeaves);
}
return height;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 421. Maximum XOR of Two Numbers in an Array
Сложность: medium
Дан целочисленный массив nums, верните максимальный результат nums[i] XOR nums[j], где 0 <= i <= j < n.
Пример:
👨💻 Алгоритм:
1⃣ Вычислите количество битов L для использования. Это длина максимального числа в двоичном представлении. Инициализируйте max_xor = 0.
2⃣ Запустите цикл от i = L−1 до i = 0 (от самого левого бита L−1 до самого правого бита 0):
Сдвигайте max_xor влево, чтобы освободить следующий бит.
Инициализируйте переменную curr_xor = max_xor | 1, установив 1 в самом правом бите max_xor. Теперь проверьте, можно ли выполнить curr_xor, используя доступные префиксы.
3⃣ Вычислите все возможные префиксы длины L−i, итерируя по nums:
Поместите в HashSet префиксы префикс текущего числа длиной L−i: num >> i.
Итерируйте по всем префиксам и проверьте, можно ли выполнить curr_xor, используя два из них: p1 ^ p2 == curr_xor. Используя свойство самопреобразования XOR p1 ^ p2 ^ p2 = p1, можно переписать это как p1 == curr_xor ^ p2 и просто проверить для каждого p, если curr_xor ^ p есть в префиксах. Если так, установите max_xor равным curr_xor, т.е. установите 1-бит в самом правом бите. В противном случае, пусть max_xor оставит 0-бит в самом правом бите.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан целочисленный массив nums, верните максимальный результат nums[i] XOR nums[j], где 0 <= i <= j < n.
Пример:
Input: nums = [3,10,5,25,2,8]
Output: 28
Explanation: The maximum result is 5 XOR 25 = 28.
Сдвигайте max_xor влево, чтобы освободить следующий бит.
Инициализируйте переменную curr_xor = max_xor | 1, установив 1 в самом правом бите max_xor. Теперь проверьте, можно ли выполнить curr_xor, используя доступные префиксы.
Поместите в HashSet префиксы префикс текущего числа длиной L−i: num >> i.
Итерируйте по всем префиксам и проверьте, можно ли выполнить curr_xor, используя два из них: p1 ^ p2 == curr_xor. Используя свойство самопреобразования XOR p1 ^ p2 ^ p2 = p1, можно переписать это как p1 == curr_xor ^ p2 и просто проверить для каждого p, если curr_xor ^ p есть в префиксах. Если так, установите max_xor равным curr_xor, т.е. установите 1-бит в самом правом бите. В противном случае, пусть max_xor оставит 0-бит в самом правом бите.
#include <vector>
#include <unordered_set>
using namespace std;
class Solution {
public:
int findMaximumXOR(vector<int>& nums) {
int maxNum = nums[0];
for (int num : nums) maxNum = max(maxNum, num);
int L = 32 - __builtin_clz(maxNum);
int maxXor = 0, currXor;
unordered_set<int> prefixes;
for (int i = L - 1; i >= 0; --i) {
maxXor <<= 1;
currXor = maxXor | 1;
prefixes.clear();
for (int num : nums) prefixes.insert(num >> i);
for (int p : prefixes) {
if (prefixes.count(currXor ^ p)) {
maxXor = currXor;
break;
}
}
}
return maxXor;
}
};
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1663. Smallest String With A Given Numeric Value
Сложность: medium
Числовое значение строчной буквы определяется ее позицией (начиная с 1) в алфавите, поэтому числовое значение a равно 1, числовое значение b равно 2, числовое значение c равно 3 и так далее.
Числовое значение строки, состоящей из строчных букв, определяется как сумма числовых значений ее символов. Например, числовое значение строки "abe" равно 1 + 2 + 5 = 8.
Вам даны два целых числа n и k. Верните лексикографически наименьшую строку длиной n с числовым значением, равным k.
Обратите внимание, что строка x лексикографически меньше строки y, если x идет перед y в словарном порядке, то есть либо x является префиксом y, либо, если i - первая позиция, где x[i] != y[i], то x[i] идет перед y[i] в алфавитном порядке.
Пример:
👨💻 Алгоритм:
1⃣ Построить строку или массив символов result для хранения выбранных символов для каждой позиции.
2⃣ Итерация от позиции 1 до n и заполнение символом каждой позиции:
Найти позиции, которые нужно заполнить, исключая текущую позицию, задаваемую переменной positionsLeft как n - position - 1.
Если значение k больше, чем positionsLeft * 26, зарезервировать числовое значение 26 (символ z) для всех оставшихся позиций positionsLeft. Вычислить значение текущей позиции, заданное переменной add, как k - (positionsLeft * 26). Вычесть рассчитанное значение add из k, чтобы найти оставшееся значение k после заполнения текущей позиции.
Иначе, заполнить текущую позицию символом a, имеющим числовое значение 1. Вычесть 1 из k, чтобы найти оставшееся значение k после заполнения текущей позиции.
3⃣ Повторять процесс, пока все позиции не будут заполнены.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Числовое значение строчной буквы определяется ее позицией (начиная с 1) в алфавите, поэтому числовое значение a равно 1, числовое значение b равно 2, числовое значение c равно 3 и так далее.
Числовое значение строки, состоящей из строчных букв, определяется как сумма числовых значений ее символов. Например, числовое значение строки "abe" равно 1 + 2 + 5 = 8.
Вам даны два целых числа n и k. Верните лексикографически наименьшую строку длиной n с числовым значением, равным k.
Обратите внимание, что строка x лексикографически меньше строки y, если x идет перед y в словарном порядке, то есть либо x является префиксом y, либо, если i - первая позиция, где x[i] != y[i], то x[i] идет перед y[i] в алфавитном порядке.
Пример:
Input: n = 3, k = 27
Output: "aay"
Explanation: The numeric value of the string is 1 + 1 + 25 = 27, and it is the smallest string with such a value and length equal to 3.
Найти позиции, которые нужно заполнить, исключая текущую позицию, задаваемую переменной positionsLeft как n - position - 1.
Если значение k больше, чем positionsLeft * 26, зарезервировать числовое значение 26 (символ z) для всех оставшихся позиций positionsLeft. Вычислить значение текущей позиции, заданное переменной add, как k - (positionsLeft * 26). Вычесть рассчитанное значение add из k, чтобы найти оставшееся значение k после заполнения текущей позиции.
Иначе, заполнить текущую позицию символом a, имеющим числовое значение 1. Вычесть 1 из k, чтобы найти оставшееся значение k после заполнения текущей позиции.
class Solution {
public:
string getSmallestString(int n, int k) {
vector<char> result(n, 'a');
for (int position = 0; position < n; ++position) {
int positionsLeft = (n - position - 1);
if (k > positionsLeft * 26) {
int add = k - (positionsLeft * 26);
result[position] = 'a' + add - 1;
k -= add;
} else {
k -= 1;
}
}
return string(result.begin(), result.end());
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 462. Minimum Moves to Equal Array Elements II
Сложность: medium
Дан массив целых чисел nums размера n, вернуть минимальное количество ходов, необходимых для того, чтобы сделать все элементы массива равными.
В одном ходе вы можете увеличить или уменьшить элемент массива на 1.
Тестовые случаи составлены так, что ответ поместится в 32-битное целое число.
Пример:
👨💻 Алгоритм:
1⃣ Найти минимальный и максимальный элементы в массиве. Пусть k будет числом, к которому должны быть приведены все элементы массива.
2⃣ Перебирать значения k в диапазоне между минимальным и максимальным элементами, вычисляя количество ходов, необходимых для каждого k.
3⃣ Определить минимальное количество ходов среди всех возможных k, что и будет конечным результатом.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив целых чисел nums размера n, вернуть минимальное количество ходов, необходимых для того, чтобы сделать все элементы массива равными.
В одном ходе вы можете увеличить или уменьшить элемент массива на 1.
Тестовые случаи составлены так, что ответ поместится в 32-битное целое число.
Пример:
Input: nums = [1,2,3]
Output: 2
Explanation:
Only two moves are needed (remember each move increments or decrements one element):
[1,2,3] => [2,2,3] => [2,2,2]
class Solution {
public:
int minMoves2(vector<int>& nums) {
long ans = LONG_MAX;
int minval = INT_MAX;
int maxval = INT_MIN;
for (int num : nums) {
minval = min(minval, num);
maxval = max(maxval, num);
}
for (int i = minval; i <= maxval; i++) {
long sum = 0;
for (int num : nums) {
sum += abs(num - i);
}
ans = min(ans, sum);
}
return (int) ans;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 282. Expression Add Operators
Сложность: hard
Дана строка num, содержащая только цифры, и целевое число target. Необходимо вернуть все возможные варианты вставки операторов +, -, * так, чтобы выражение вычислялось в target. Ведущие нули в операндах недопустимы.
Пример:
👨💻 Алгоритм
1⃣ Инициализация
Запускаем рекурсивную функцию, передавая текущие параметры: индекс, предыдущий операнд, текущий операнд, текущее значение и список с операциями.
2⃣ Обработка каждого символа
На каждом шаге рассматриваем, хотим ли мы продолжать накапливать цифры текущего операнда, либо уже вставляем оператор и переходим к следующей части выражения.
3⃣ Учет всех операторов
Рассматриваем операции +, - и *, для каждой пересчитываем значение с учетом порядка операций. Используем previousOperand для корректного учета * в выражении.
😎 Решение
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дана строка num, содержащая только цифры, и целевое число target. Необходимо вернуть все возможные варианты вставки операторов +, -, * так, чтобы выражение вычислялось в target. Ведущие нули в операндах недопустимы.
Пример:
Input: num = "232", target = 8
Output: ["2*3+2","2+3*2"]
Запускаем рекурсивную функцию, передавая текущие параметры: индекс, предыдущий операнд, текущий операнд, текущее значение и список с операциями.
На каждом шаге рассматриваем, хотим ли мы продолжать накапливать цифры текущего операнда, либо уже вставляем оператор и переходим к следующей части выражения.
Рассматриваем операции +, - и *, для каждой пересчитываем значение с учетом порядка операций. Используем previousOperand для корректного учета * в выражении.
class Solution {
private:
vector<string> answer;
string digits;
long long target;
void recurse(int index, long long prevOperand, long long currentOperand, long long value, vector<string>& ops) {
if (index == digits.size()) {
if (value == target && currentOperand == 0) {
string expression = accumulate(ops.begin(), ops.end(), string(""));
answer.push_back(expression);
}
return;
}
currentOperand = currentOperand * 10 + (digits[index] - '0');
string currentValRep = to_string(currentOperand);
if (currentOperand > 0) {
recurse(index + 1, prevOperand, currentOperand, value, ops);
}
// +
ops.push_back("+");
ops.push_back(currentValRep);
recurse(index + 1, currentOperand, 0, value + currentOperand, ops);
ops.pop_back(); ops.pop_back();
if (!ops.empty()) {
// -
ops.push_back("-");
ops.push_back(currentValRep);
recurse(index + 1, -currentOperand, 0, value - currentOperand, ops);
ops.pop_back(); ops.pop_back();
// *
ops.push_back("*");
ops.push_back(currentValRep);
recurse(index + 1, prevOperand * currentOperand, 0, value - prevOperand + (prevOperand * currentOperand), ops);
ops.pop_back(); ops.pop_back();
}
}
public:
vector<string> addOperators(string num, int target) {
if (num.empty()) return {};
this->digits = num;
this->target = target;
vector<string> ops;
recurse(0, 0, 0, 0, ops);
return answer;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1382. Balance a Binary Search Tree
Сложность: medium
Дан корень бинарного дерева поиска. Верните сбалансированное бинарное дерево поиска с теми же значениями узлов. Если существует более одного ответа, верните любой из них.
Бинарное дерево поиска считается сбалансированным, если глубина двух поддеревьев каждого узла никогда не отличается более чем на 1.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация. Создайте пустой список inorder для хранения значений узлов после обхода в порядке возрастания.
2⃣ Выполнение обхода в порядке возрастания. Обойдите бинарное дерево поиска (BST) и заполните список inorder значениями узлов в отсортированном порядке.
3⃣ Перестроение сбалансированного BST. Определите рекурсивную функцию createBalancedBST, которая принимает список inorder, начальный индекс и конечный индекс в качестве параметров. Если начальный индекс больше конечного, верните null (или эквивалент). Вычислите средний индекс как середину текущего диапазона. Создайте новый узел дерева со значением в среднем индексе. Рекурсивно создайте левое поддерево, используя левую половину текущего диапазона. Рекурсивно создайте правое поддерево, используя правую половину текущего диапазона. Верните корень вновь построенного сбалансированного BST.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан корень бинарного дерева поиска. Верните сбалансированное бинарное дерево поиска с теми же значениями узлов. Если существует более одного ответа, верните любой из них.
Бинарное дерево поиска считается сбалансированным, если глубина двух поддеревьев каждого узла никогда не отличается более чем на 1.
Пример:
Input: root = [1,null,2,null,3,null,4,null,null]
Output: [2,1,3,null,null,null,4]
Explanation: This is not the only correct answer, [3,1,4,null,2] is also correct.
class Solution {
public:
TreeNode* balanceBST(TreeNode* root) {
if (!root) return nullptr;
TreeNode* vineHead = new TreeNode(0);
vineHead->right = root;
TreeNode* current = vineHead;
while (current->right) {
if (current->right->left) {
rightRotate(current, current->right);
} else {
current = current->right;
}
}
int nodeCount = 0;
current = vineHead->right;
while (current) {
++nodeCount;
current = current->right;
}
int m = pow(2, floor(log2(nodeCount + 1))) - 1;
makeRotations(vineHead, nodeCount - m);
while (m > 1) {
m /= 2;
makeRotations(vineHead, m);
}
TreeNode* balancedRoot = vineHead->right;
delete vineHead;
return balancedRoot;
}
private:
void rightRotate(TreeNode* parent, TreeNode* node) {
TreeNode* tmp = node->left;
node->left = tmp->right;
tmp->right = node;
parent->right = tmp;
}
void leftRotate(TreeNode* parent, TreeNode* node) {
TreeNode* tmp = node->right;
node->right = tmp->left;
tmp->left = node;
parent->right = tmp;
}
void makeRotations(TreeNode* vineHead, int count) {
TreeNode* current = vineHead;
for (int i = 0; i < count; ++i) {
TreeNode* tmp = current->right;
leftRotate(current, tmp);
current = current->right;
}
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 765. Couples Holding Hands
Сложность: hard
Есть n пар, сидящих на 2n местах, расположенных в ряд, и они хотят держаться за руки.
Люди и места представлены массивом целых чисел row, где row[i] — это ID человека, сидящего на i-м месте. Пары пронумерованы по порядку: первая пара — (0, 1), вторая пара — (2, 3) и так далее, до последней пары — (2n - 2, 2n - 1).
Верните минимальное количество перестановок, чтобы каждая пара сидела рядом. Перестановка состоит из выбора любых двух человек, которые встают и меняются местами.
Пример:
👨💻 Алгоритм:
1⃣ Мы могли бы предположить без доказательства, что решение, при котором мы делаем людей на каждом диване счастливыми по порядку, является оптимальным. Это предположение сильнее, чем гипотеза о жадном подходе, но кажется разумным, поскольку при каждом ходе мы делаем хотя бы одну пару счастливой.
2⃣ При таком предположении, для какого-то дивана с несчастливыми людьми X и Y, мы либо заменяем Y на партнера X, либо заменяем X на партнера Y. Для каждой из двух возможностей мы можем попробовать оба варианта, используя подход с возвратом.
3⃣ Для каждого дивана с двумя возможностями (т.е. оба человека на диване несчастливы) мы попробуем первый вариант, найдем ответ как ans1, затем отменим наш ход и попробуем второй вариант, найдем связанный ответ как ans2, отменим наш ход и затем вернем наименьший ответ.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Есть n пар, сидящих на 2n местах, расположенных в ряд, и они хотят держаться за руки.
Люди и места представлены массивом целых чисел row, где row[i] — это ID человека, сидящего на i-м месте. Пары пронумерованы по порядку: первая пара — (0, 1), вторая пара — (2, 3) и так далее, до последней пары — (2n - 2, 2n - 1).
Верните минимальное количество перестановок, чтобы каждая пара сидела рядом. Перестановка состоит из выбора любых двух человек, которые встают и меняются местами.
Пример:
Input: row = [0,2,1,3]
Output: 1
Explanation: We only need to swap the second (row[1]) and third (row[2]) person.
class Solution {
public:
int N;
vector<vector<int>> pairs;
int minSwapsCouples(vector<int>& row) {
N = row.size() / 2;
pairs.resize(N, vector<int>(2));
for (int i = 0; i < N; ++i) {
pairs[i][0] = row[2 * i] / 2;
pairs[i][1] = row[2 * i + 1] / 2;
}
return solve(0);
}
void swap(int a, int b, int c, int d) {
int t = pairs[a][b];
pairs[a][b] = pairs[c][d];
pairs[c][d] = t;
}
int solve(int i) {
if (i == N) return 0;
int x = pairs[i][0], y = pairs[i][1];
if (x == y) return solve(i + 1);
int jx = 0, kx = 0, jy = 0, ky = 0;
for (int j = i + 1; j < N; ++j) {
for (int k = 0; k <= 1; ++k) {
if (pairs[j][k] == x) { jx = j; kx = k; }
if (pairs[j][k] == y) { jy = j; ky = k; }
}
}
swap(i, 1, jx, kx);
int ans1 = 1 + solve(i + 1);
swap(i, 1, jx, kx);
swap(i, 0, jy, ky);
int ans2 = 1 + solve(i + 1);
swap(i, 0, jy, ky);
return min(ans1, ans2);
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 826. Most Profit Assigning Work
Сложность: medium
У вас есть n заданий и m рабочих. Вам даны три массива: difficulty, profit и worker, где:
difficulty[i] и profit[i] — сложность и прибыль i-го задания,
worker[j] — способность j-го рабочего (т.е. j-й рабочий может выполнить задание со сложностью не больше worker[j]).
Каждому рабочему можно назначить не более одного задания, но одно задание может быть выполнено несколько раз.
Например, если три рабочих выполняют одно и то же задание с оплатой $1, общая прибыль составит $3. Если рабочий не может выполнить ни одно задание, его прибыль равна $0.
Верните максимальную прибыль, которую можно получить после распределения рабочих по заданиям.
Пример:
👨💻 Алгоритм:
1⃣ Создание и сортировка профиля работы
Инициализируйте массив пар jobProfile с {0, 0}. Для каждого задания добавьте {difficulty[i], profit[i]} в jobProfile. Отсортируйте jobProfile по возрастанию сложности.
2⃣ Обновление максимальной прибыли для каждой сложности
Обновите значение прибыли каждой сложности, чтобы оно было максимальным из текущего значения и предыдущего значения прибыли.
3⃣ Вычисление максимальной прибыли
Для каждой способности рабочего используйте бинарный поиск, чтобы найти задание с наибольшей прибылью, которую может выполнить этот рабочий. Суммируйте полученную прибыль для всех рабочих и верните ее.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
У вас есть n заданий и m рабочих. Вам даны три массива: difficulty, profit и worker, где:
difficulty[i] и profit[i] — сложность и прибыль i-го задания,
worker[j] — способность j-го рабочего (т.е. j-й рабочий может выполнить задание со сложностью не больше worker[j]).
Каждому рабочему можно назначить не более одного задания, но одно задание может быть выполнено несколько раз.
Например, если три рабочих выполняют одно и то же задание с оплатой $1, общая прибыль составит $3. Если рабочий не может выполнить ни одно задание, его прибыль равна $0.
Верните максимальную прибыль, которую можно получить после распределения рабочих по заданиям.
Пример:
Input: difficulty = [2,4,6,8,10], profit = [10,20,30,40,50], worker = [4,5,6,7]
Output: 100
Explanation: Workers are assigned jobs of difficulty [4,4,6,6] and they get a profit of [20,20,30,30] separately.
Инициализируйте массив пар jobProfile с {0, 0}. Для каждого задания добавьте {difficulty[i], profit[i]} в jobProfile. Отсортируйте jobProfile по возрастанию сложности.
Обновите значение прибыли каждой сложности, чтобы оно было максимальным из текущего значения и предыдущего значения прибыли.
Для каждой способности рабочего используйте бинарный поиск, чтобы найти задание с наибольшей прибылью, которую может выполнить этот рабочий. Суммируйте полученную прибыль для всех рабочих и верните ее.
class Solution {
public:
int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker) {
vector<pair<int, int>> jobProfile = {{0, 0}};
for (int i = 0; i < difficulty.size(); ++i) {
jobProfile.push_back({difficulty[i], profit[i]});
}
sort(jobProfile.begin(), jobProfile.end());
for (int i = 1; i < jobProfile.size(); ++i) {
jobProfile[i].second = max(jobProfile[i].second, jobProfile[i - 1].second);
}
int netProfit = 0;
for (int ability : worker) {
int l = 0, r = jobProfile.size() - 1, jobProfit = 0;
while (l <= r) {
int mid = (l + r) / 2;
if (jobProfile[mid].first <= ability) {
jobProfit = max(jobProfit, jobProfile[mid].second);
l = mid + 1;
} else {
r = mid - 1;
}
}
netProfit += jobProfit;
}
return netProfit;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 74. Search a 2D Matrix
Сложность: medium
Вам дана матрица из целых чисел размером m на n с следующими двумя свойствами:
Каждая строка отсортирована в порядке не убывания.
Первое число каждой строки больше последнего числа предыдущей строки.
Дано целое число target. Верните true, если target присутствует в матрице, и false в противном случае.
Вы должны написать решение с временной сложностью O(log(m * n)).
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте индексы слева и справа: left = 0 и right = m * n - 1.
2⃣ Пока left <= right:
вычисляйте pivot_idx = (left + right) / 2.
3⃣ Получите координаты элемента: row = pivot_idx // n, col = pivot_idx % n,
затем сравните pivot_element = matrix[row][col] с target, чтобы решить, в какой части продолжать поиск.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дана матрица из целых чисел размером m на n с следующими двумя свойствами:
Каждая строка отсортирована в порядке не убывания.
Первое число каждой строки больше последнего числа предыдущей строки.
Дано целое число target. Верните true, если target присутствует в матрице, и false в противном случае.
Вы должны написать решение с временной сложностью O(log(m * n)).
Пример:
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
Output: true
вычисляйте pivot_idx = (left + right) / 2.
затем сравните pivot_element = matrix[row][col] с target, чтобы решить, в какой части продолжать поиск.
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size();
if (m == 0)
return false;
int n = matrix[0].size();
int left = 0, right = m * n - 1;
int pivotIdx, pivotElement;
while (left <= right) {
pivotIdx = (left + right) / 2;
pivotElement = matrix[pivotIdx / n][pivotIdx % n];
if (target == pivotElement)
return true;
else {
if (target < pivotElement)
right = pivotIdx - 1;
else
left = pivotIdx + 1;
}
}
return false;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1202. Smallest String With Swaps
Сложность: medium
Вам дана строка s и массив пар индексов в строке pairs, где pairs[i] = [a, b] указывает на 2 индекса (начиная с 0) в строке.
Вы можете менять местами символы в любой паре индексов в заданных парах любое количество раз.
Верните лексикографически наименьшую строку, которую можно получить после выполнения перестановок.
Пример:
👨💻 Алгоритм:
1⃣ Создание списка смежности:
Итеративно пройдитесь по парам и создайте список смежности adj, где adj[source] содержит все смежные вершины вершины source.
2⃣ Обход графа и сбор индексов и символов:
Итеративно пройдитесь по индексам от 0 до s.size() - 1. Для каждого индекса vertex:
- выполните DFS, если вершина еще не посещена (visited[vertex] = false).
- во время выполнения DFS сохраняйте vertex в список indices и символ s[vertex] в список characters.
3⃣ Сортировка и построение результирующей строки:
Отсортируйте списки indices и characters.
Пройдитесь по индексам и символам, и разместите i-й символ в i-й индекс результирующей строки smallestString.
Верните smallestString.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дана строка s и массив пар индексов в строке pairs, где pairs[i] = [a, b] указывает на 2 индекса (начиная с 0) в строке.
Вы можете менять местами символы в любой паре индексов в заданных парах любое количество раз.
Верните лексикографически наименьшую строку, которую можно получить после выполнения перестановок.
Пример:
Input: s = "dcab", pairs = [[0,3],[1,2]]
Output: "bacd"
Explaination:
Swap s[0] and s[3], s = "bcad"
Swap s[1] and s[2], s = "bacd"
Итеративно пройдитесь по парам и создайте список смежности adj, где adj[source] содержит все смежные вершины вершины source.
Итеративно пройдитесь по индексам от 0 до s.size() - 1. Для каждого индекса vertex:
- выполните DFS, если вершина еще не посещена (visited[vertex] = false).
- во время выполнения DFS сохраняйте vertex в список indices и символ s[vertex] в список characters.
Отсортируйте списки indices и characters.
Пройдитесь по индексам и символам, и разместите i-й символ в i-й индекс результирующей строки smallestString.
Верните smallestString.
class Solution {
public:
string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) {
int n = s.size();
vector<vector<int>> adj(n);
for (auto& p : pairs) {
adj[p[0]].push_back(p[1]);
adj[p[1]].push_back(p[0]);
}
vector<bool> visited(n, false);
vector<char> sArray(s.begin(), s.end());
function<void(int, vector<int>&, vector<char>&)> dfs = [&](int node, vector<int>& indices, vector<char>& chars) {
visited[node] = true;
indices.push_back(node);
chars.push_back(sArray[node]);
for (int neighbor : adj[node]) {
if (!visited[neighbor]) {
dfs(neighbor, indices, chars);
}
}
};
for (int i = 0; i < n; ++i) {
if (!visited[i]) {
vector<int> indices;
vector<char> chars;
dfs(i, indices, chars);
sort(indices.begin(), indices.end());
sort(chars.begin(), chars.end());
for (int j = 0; j < indices.size(); ++j) {
sArray[indices[j]] = chars[j];
}
}
}
return string(sArray.begin(), sArray.end());
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 211. Design Add and Search Words Data Structure
Сложность: medium
Необходимо реализовать структуру данных, которая позволяет:
addWord(word) — добавлять слова
search(word) — искать слова с поддержкой символа ".", обозначающего любую букву
Пример:
👨💻 Алгоритм:
1⃣ Добавление слова (addWord)
Используем структуру Trie (префиксное дерево).
Если буква из слова отсутствует в текущем узле, создаём новую.
После вставки всех букв устанавливаем флаг word = true.
2⃣ Поиск слова (search)
Запускаем рекурсивную функцию searchInNode(word, node).
Если текущий символ — ., пробуем все возможные пути в дереве.
Если обычный символ — продолжаем по соответствующей ветке.
Если путь закончился, проверяем флаг word.
3⃣ Обработка подстановки (.)
Поддержка символа . реализуется через рекурсивный вызов searchInNode для всех дочерних узлов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Необходимо реализовать структуру данных, которая позволяет:
addWord(word) — добавлять слова
search(word) — искать слова с поддержкой символа ".", обозначающего любую букву
Пример:
pgsqlКопироватьРедактироватьWordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord("bad");
wordDictionary.addWord("dad");
wordDictionary.addWord("mad");
wordDictionary.search("pad"); // false
wordDictionary.search("bad"); // true
wordDictionary.search(".ad"); // true
wordDictionary.search("b.."); // true
Используем структуру Trie (префиксное дерево).
Если буква из слова отсутствует в текущем узле, создаём новую.
После вставки всех букв устанавливаем флаг word = true.
Запускаем рекурсивную функцию searchInNode(word, node).
Если текущий символ — ., пробуем все возможные пути в дереве.
Если обычный символ — продолжаем по соответствующей ветке.
Если путь закончился, проверяем флаг word.
Поддержка символа . реализуется через рекурсивный вызов searchInNode для всех дочерних узлов.
struct TrieNode {
unordered_map<char, TrieNode*> children;
bool word = false;
};
class WordDictionary {
TrieNode* trie;
public:
WordDictionary() { trie = new TrieNode(); }
void addWord(string word) {
TrieNode* node = trie;
for (char ch : word) {
if (!node->children.count(ch)) {
node->children[ch] = new TrieNode();
}
node = node->children[ch];
}
node->word = true;
}
bool searchInNode(string word, TrieNode* node) {
for (int i = 0; i < word.length(); ++i) {
char ch = word[i];
if (!node->children.count(ch)) {
if (ch == '.') {
for (auto x : node->children) {
TrieNode* child = x.second;
if (searchInNode(word.substr(i + 1), child)) {
return true;
}
}
}
return false;
} else {
node = node->children[ch];
}
}
return node->word;
}
bool search(string word) { return searchInNode(word, trie); }
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1429. First Unique Number
Сложность: medium
У вас есть очередь целых чисел, необходимо извлечь первый уникальный элемент из очереди.
Реализуйте класс FirstUnique:
- FirstUnique(int[] nums) Инициализирует объект числами в очереди.
- int showFirstUnique() возвращает значение первого уникального элемента в очереди и возвращает -1, если такого элемента нет.
- void add(int value) вставляет значение в очередь.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте объект FirstUnique с числами в очереди, добавляя их в структуру данных для отслеживания уникальности и порядка.
2⃣ Метод showFirstUnique возвращает значение первого уникального элемента в очереди, если таковой существует, или -1, если уникальных элементов нет.
3⃣ Метод add добавляет новое значение в очередь. Если значение уже было добавлено ранее, обновляет его статус уникальности и удаляет его из множества уникальных значений, если оно больше не уникально.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
У вас есть очередь целых чисел, необходимо извлечь первый уникальный элемент из очереди.
Реализуйте класс FirstUnique:
- FirstUnique(int[] nums) Инициализирует объект числами в очереди.
- int showFirstUnique() возвращает значение первого уникального элемента в очереди и возвращает -1, если такого элемента нет.
- void add(int value) вставляет значение в очередь.
Пример:
Input:
["FirstUnique","showFirstUnique","add","showFirstUnique","add","showFirstUnique","add","showFirstUnique"]
[[[2,3,5]],[],[5],[],[2],[],[3],[]]
Output:
[null,2,null,2,null,3,null,-1]
Explanation:
FirstUnique firstUnique = new FirstUnique([2,3,5]);
firstUnique.showFirstUnique(); // return 2
firstUnique.add(5); // the queue is now [2,3,5,5]
firstUnique.showFirstUnique(); // return 2
firstUnique.add(2); // the queue is now [2,3,5,5,2]
firstUnique.showFirstUnique(); // return 3
firstUnique.add(3); // the queue is now [2,3,5,5,2,3]
firstUnique.showFirstUnique(); // return -1
#include <unordered_map>
#include <unordered_set>
#include <list>
class FirstUnique {
public:
FirstUnique(vector<int>& nums) {
for (int num : nums) {
add(num);
}
}
int showFirstUnique() {
if (!queue.empty()) {
return queue.front();
}
return -1;
}
void add(int value) {
if (isUnique.find(value) == isUnique.end()) {
isUnique[value] = true;
queue.push_back(value);
} else if (isUnique[value]) {
isUnique[value] = false;
queue.remove(value);
}
}
private:
list<int> queue;
unordered_map<int, bool> isUnique;
};
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM