Задача: 1214. Two Sum BSTs
Сложность: medium
Даны корни двух бинарных деревьев поиска, root1 и root2, верните true, если и только если существует узел в первом дереве и узел во втором дереве, значения которых в сумме равны заданному целому числу target.
Пример:
👨💻 Алгоритм:
1⃣Создайте два пустых множества node_set1 и node_set2. Выполните обход дерева root1, добавляя значения каждого узла в node_set1, и выполните обход дерева root2, добавляя значения каждого узла в node_set2.
2⃣Итерация по элементам в node_set1: для каждого элемента value1 проверяйте, находится ли target - value1 в node_set2.
3⃣Если target - value1 находится в node_set2, верните true. Если после завершения итерации не найдено ни одной подходящей пары, верните false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Даны корни двух бинарных деревьев поиска, root1 и root2, верните true, если и только если существует узел в первом дереве и узел во втором дереве, значения которых в сумме равны заданному целому числу target.
Пример:
Input: root1 = [0,-10,10], root2 = [5,1,7,0,2], target = 18
Output: false
👨💻 Алгоритм:
1⃣Создайте два пустых множества node_set1 и node_set2. Выполните обход дерева root1, добавляя значения каждого узла в node_set1, и выполните обход дерева root2, добавляя значения каждого узла в node_set2.
2⃣Итерация по элементам в node_set1: для каждого элемента value1 проверяйте, находится ли target - value1 в node_set2.
3⃣Если target - value1 находится в node_set2, верните true. Если после завершения итерации не найдено ни одной подходящей пары, верните false.
😎 Решение:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
void dfs(TreeNode* node, unordered_set<int>& nodeSet) {
if (!node) return;
dfs(node->left, nodeSet);
nodeSet.insert(node->val);
dfs(node->right, nodeSet);
}
public:
bool twoSumBSTs(TreeNode* root1, TreeNode* root2, int target) {
unordered_set<int> nodeSet1, nodeSet2;
dfs(root1, nodeSet1);
dfs(root2, nodeSet2);
for (int value1 : nodeSet1) {
if (nodeSet2.count(target - value1)) {
return true;
}
}
return false;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 859. Buddy Strings
Сложность: easy
Даны две строки s и goal. Верните true, если вы можете поменять местами две буквы в s так, чтобы результат был равен goal, в противном случае верните false.
Обмен буквами определяется как взятие двух индексов i и j (нумерация с 0), таких что i != j, и обмен символов в s[i] и s[j].
Например, обмен символов на индексах 0 и 2 в строке "abcd" приводит к "cbad".
Пример:
👨💻 Алгоритм:
1⃣Если количество символов в строках s и goal разное, возвращаем false. Если s == goal, используем хеш-таблицу или массив из 26 элементов для хранения частоты каждого символа в строке s. Если какой-либо символ встречается более одного раза, можно поменять местами две одинаковые буквы, возвращаем true. Иначе возвращаем false.
2⃣Иначе, если s != goal, инициализируем firstIndex и secondIndex значениями -1 для хранения индексов символов в строке s, которые отличаются от символов в строке goal на тех же индексах. Итерируем по каждому индексу i в строке s: если символы s[i] и goal[i] разные, сохраняем текущий индекс. Если firstIndex == -1, обновляем firstIndex = i. Если firstIndex != -1, но secondIndex == -1, обновляем secondIndex = i. Если оба индекса уже обновлены, возвращаем false.
3⃣Если обновлен только firstIndex, возвращаем false. Иначе, все символы обеих строк одинаковы, кроме двух индексов. Поэтому s[firstIndex] должен быть равен goal[secondIndex], и s[secondIndex] должен быть равен goal[firstIndex], чтобы строки стали равны после обмена.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Даны две строки s и goal. Верните true, если вы можете поменять местами две буквы в s так, чтобы результат был равен goal, в противном случае верните false.
Обмен буквами определяется как взятие двух индексов i и j (нумерация с 0), таких что i != j, и обмен символов в s[i] и s[j].
Например, обмен символов на индексах 0 и 2 в строке "abcd" приводит к "cbad".
Пример:
Input: s = "ab", goal = "ba"
Output: true
Explanation: You can swap s[0] = 'a' and s[1] = 'b' to get "ba", which is equal to goal.
👨💻 Алгоритм:
1⃣Если количество символов в строках s и goal разное, возвращаем false. Если s == goal, используем хеш-таблицу или массив из 26 элементов для хранения частоты каждого символа в строке s. Если какой-либо символ встречается более одного раза, можно поменять местами две одинаковые буквы, возвращаем true. Иначе возвращаем false.
2⃣Иначе, если s != goal, инициализируем firstIndex и secondIndex значениями -1 для хранения индексов символов в строке s, которые отличаются от символов в строке goal на тех же индексах. Итерируем по каждому индексу i в строке s: если символы s[i] и goal[i] разные, сохраняем текущий индекс. Если firstIndex == -1, обновляем firstIndex = i. Если firstIndex != -1, но secondIndex == -1, обновляем secondIndex = i. Если оба индекса уже обновлены, возвращаем false.
3⃣Если обновлен только firstIndex, возвращаем false. Иначе, все символы обеих строк одинаковы, кроме двух индексов. Поэтому s[firstIndex] должен быть равен goal[secondIndex], и s[secondIndex] должен быть равен goal[firstIndex], чтобы строки стали равны после обмена.
😎 Решение:
class Solution {
public:
bool buddyStrings(string s, string goal) {
if (s.size() != goal.size()) return false;
if (s == goal) {
vector<int> freq(26, 0);
for (char ch : s) {
if (++freq[ch - 'a'] > 1) return true;
}
return false;
}
int firstIndex = -1, secondIndex = -1;
for (int i = 0; i < s.size(); ++i) {
if (s[i] != goal[i]) {
if (firstIndex == -1) firstIndex = i;
else if (secondIndex == -1) secondIndex = i;
else return false;
}
}
return secondIndex != -1 &&
s[firstIndex] == goal[secondIndex] &&
s[secondIndex] == goal[firstIndex];
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 16. 3Sum Closest
Сложность: medium
Дан массив целых чисел nums и целое число target.
Найди такую тройку чисел в массиве, сумма которых наиболее близка к target, и верни эту сумму.
Гарантируется, что только одно решение существует.
Пример:
👨💻 Алгоритм:
1⃣Отсортировать массив, чтобы удобно применять технику двух указателей.
2⃣Для каждого числа nums[i], зафиксировать его и искать пару чисел в подмассиве справа с помощью двух указателей (front, back), чтобы сумма тройки была ближе всего к target.
3⃣Обновлять текущую лучшую сумму, если новая тройка ближе к target, чем предыдущая. Вернуть финальный результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив целых чисел nums и целое число target.
Найди такую тройку чисел в массиве, сумма которых наиболее близка к target, и верни эту сумму.
Гарантируется, что только одно решение существует.
Пример:
Input: nums = [-1,2,1,-4], target = 1
Output: 2
👨💻 Алгоритм:
1⃣Отсортировать массив, чтобы удобно применять технику двух указателей.
2⃣Для каждого числа nums[i], зафиксировать его и искать пару чисел в подмассиве справа с помощью двух указателей (front, back), чтобы сумма тройки была ближе всего к target.
3⃣Обновлять текущую лучшую сумму, если новая тройка ближе к target, чем предыдущая. Вернуть финальный результат.
😎 Решение:
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int sum = nums[0] + nums[1] + nums[2];
int sum1 = 0;
for (int i = 0; i < nums.size(); i++) {
int front = i + 1;
int back = nums.size() - 1;
while (front < back) {
sum1 = nums[i] + nums[front] + nums[back];
if (abs(sum1 - target) <= abs(sum - target)) {
sum = sum1;
}
if (sum1 > target)
back--;
else if (sum1 < target)
front++;
else
return sum1;
}
}
return sum;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 1026. Maximum Difference Between Node and Ancestor
Сложность: medium
Учитывая корень бинарного дерева, найдите максимальное значение v, для которого существуют различные вершины a и b, где v = |a.val - b.val| и a является предком b. Вершина a является предком b, если: любой ребенок a равен b или любой ребенок a является предком b.
Пример:
👨💻 Алгоритм:
1⃣Рекурсивный обход дерева:
Используйте рекурсивную функцию для обхода дерева. Передавайте минимальное и максимальное значения, встреченные на пути от корня к текущему узлу.
2⃣Обновление максимальной разницы:
При посещении каждого узла обновляйте минимальное и максимальное значения. Вычисляйте разницу между текущим значением узла и минимальным и максимальным значениями на пути. Обновляйте максимальную разницу, если текущая разница больше.
3⃣Рекурсивный вызов для детей:
Рекурсивно вызывайте функцию для левого и правого поддерева, передавая обновленные минимальное и максимальное значения.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Учитывая корень бинарного дерева, найдите максимальное значение v, для которого существуют различные вершины a и b, где v = |a.val - b.val| и a является предком b. Вершина a является предком b, если: любой ребенок a равен b или любой ребенок a является предком b.
Пример:
Input: root = [8,3,10,1,6,null,14,null,null,4,7,13]
Output: 7
👨💻 Алгоритм:
1⃣Рекурсивный обход дерева:
Используйте рекурсивную функцию для обхода дерева. Передавайте минимальное и максимальное значения, встреченные на пути от корня к текущему узлу.
2⃣Обновление максимальной разницы:
При посещении каждого узла обновляйте минимальное и максимальное значения. Вычисляйте разницу между текущим значением узла и минимальным и максимальным значениями на пути. Обновляйте максимальную разницу, если текущая разница больше.
3⃣Рекурсивный вызов для детей:
Рекурсивно вызывайте функцию для левого и правого поддерева, передавая обновленные минимальное и максимальное значения.
😎 Решение:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
int maxAncestorDiff(TreeNode* root) {
return dfs(root, root->val, root->val);
}
private:
int dfs(TreeNode* node, int min_val, int max_val) {
if (!node) return max_val - min_val;
min_val = min(min_val, node->val);
max_val = max(max_val, node->val);
int left = dfs(node->left, min_val, max_val);
int right = dfs(node->right, min_val, max_val);
return max(left, right);
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 1261. Find Elements in a Contaminated Binary Tree
Сложность: medium
Дано двоичное дерево со следующими правилами: root.val == 0 Если treeNode.val == x и treeNode.left != null, то treeNode.left.val == 2 * x + 1 Если treeNode.val == x и treeNode.right != null, то treeNode.right.val == 2 * x + 2 Теперь двоичное дерево загрязнено, то есть все treeNode.val были изменены на -1. Реализация класса FindElements: FindElements(TreeNode* root) Инициализирует объект с загрязненным двоичным деревом и восстанавливает его. bool find(int target) Возвращает true, если целевое значение существует в восстановленном двоичном дереве.
Пример:
👨💻 Алгоритм:
1⃣Восстановление дерева: Начните с корневого узла, установите его значение на 0. Затем рекурсивно восстановите значения для всех узлов, используя правила left.val = 2 * parent.val + 1 и right.val = 2 * parent.val + 2.
2⃣Сохранение значений: Используйте структуру данных, такую как множество (set), для хранения всех восстановленных значений узлов.
3⃣Поиск значений: Реализуйте метод поиска, который проверяет, содержится ли целевое значение в множестве восстановленных значений.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дано двоичное дерево со следующими правилами: root.val == 0 Если treeNode.val == x и treeNode.left != null, то treeNode.left.val == 2 * x + 1 Если treeNode.val == x и treeNode.right != null, то treeNode.right.val == 2 * x + 2 Теперь двоичное дерево загрязнено, то есть все treeNode.val были изменены на -1. Реализация класса FindElements: FindElements(TreeNode* root) Инициализирует объект с загрязненным двоичным деревом и восстанавливает его. bool find(int target) Возвращает true, если целевое значение существует в восстановленном двоичном дереве.
Пример:
Input
["FindElements","find","find"]
[[[-1,null,-1]],[1],[2]]
Output
[null,false,true]
👨💻 Алгоритм:
1⃣Восстановление дерева: Начните с корневого узла, установите его значение на 0. Затем рекурсивно восстановите значения для всех узлов, используя правила left.val = 2 * parent.val + 1 и right.val = 2 * parent.val + 2.
2⃣Сохранение значений: Используйте структуру данных, такую как множество (set), для хранения всех восстановленных значений узлов.
3⃣Поиск значений: Реализуйте метод поиска, который проверяет, содержится ли целевое значение в множестве восстановленных значений.
😎 Решение:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class FindElements {
public:
TreeNode* root;
unordered_set<int> values;
FindElements(TreeNode* root) {
this->root = root;
root->val = 0;
values.insert(0);
recover(root);
}
void recover(TreeNode* node) {
if (node->left != nullptr) {
node->left->val = 2 * node->val + 1;
values.insert(node->left->val);
recover(node->left);
}
if (node->right != nullptr) {
node->right->val = 2 * node->val + 2;
values.insert(node->right->val);
recover(node->right);
}
}
bool find(int target) {
return values.find(target) != values.end();
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 17. Letter Combinations of a Phone Number
Сложность: medium
Дана строка, содержащая цифры от 2 до 9. Необходимо вернуть все возможные комбинации букв, которые может представлять эта строка, согласно клавиатуре мобильного телефона.
Цифра 1 не используется, и для неё нет соответствующих букв.
Пример:
👨💻 Алгоритм:
1⃣Используем рекурсию и бэктрекинг. Для каждой цифры подставляем все возможные буквы.
2⃣На каждом шаге рекурсивно добавляем буквы для текущей цифры к текущей строке.
3⃣Когда строка достигла длины исходных digits — добавляем комбинацию в результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дана строка, содержащая цифры от 2 до 9. Необходимо вернуть все возможные комбинации букв, которые может представлять эта строка, согласно клавиатуре мобильного телефона.
Цифра 1 не используется, и для неё нет соответствующих букв.
Пример:
Input: digits = "23"
Output: ["ad","ae","af","bd","be","bf","cd","ce","cf"]
👨💻 Алгоритм:
1⃣Используем рекурсию и бэктрекинг. Для каждой цифры подставляем все возможные буквы.
2⃣На каждом шаге рекурсивно добавляем буквы для текущей цифры к текущей строке.
3⃣Когда строка достигла длины исходных digits — добавляем комбинацию в результат.
😎 Решение:
class Solution {
public:
void find(string digits, vector<string> v, vector<string>& res, string s, int k) {
if (k >= digits.size()) {
res.push_back(s);
return;
}
int a = digits[k] - '0';
for (int i = 0; i < v[a].size(); i++) {
s += v[a][i];
find(digits, v, res, s, k + 1);
s.pop_back();
}
}
vector<string> letterCombinations(string digits) {
vector<string> res;
if (digits.empty()) return res;
vector<string> v = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
string s = "";
find(digits, v, res, s, 0);
return res;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 507. Perfect Number
Сложность: easy
Совершенное число — это положительное целое число, которое равно сумме своих положительных делителей, исключая само число. Делитель целого числа x — это целое число, которое может делить x нацело.
Дано целое число n, верните true, если n является совершенным числом, в противном случае верните false.
Пример:
👨💻 Алгоритм:
1⃣Инициализация
Если число num меньше или равно 0, вернуть false. Инициализируйте переменную sum значением 0.
2⃣Поиск делителей и вычисление суммы
Переберите числа от 1 до квадратного корня num. Если число является делителем num, добавьте его к sum. Если делитель не равен квадратному корню num, добавьте к sum также результат деления num на делитель.
3⃣Проверка на совершенное число
Вычтите num из sum. Если результат равен num, вернуть true, иначе вернуть false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Совершенное число — это положительное целое число, которое равно сумме своих положительных делителей, исключая само число. Делитель целого числа x — это целое число, которое может делить x нацело.
Дано целое число n, верните true, если n является совершенным числом, в противном случае верните false.
Пример:
Input: num = 28
Output: true
Explanation: 28 = 1 + 2 + 4 + 7 + 14
1, 2, 4, 7, and 14 are all divisors of 28.
👨💻 Алгоритм:
1⃣Инициализация
Если число num меньше или равно 0, вернуть false. Инициализируйте переменную sum значением 0.
2⃣Поиск делителей и вычисление суммы
Переберите числа от 1 до квадратного корня num. Если число является делителем num, добавьте его к sum. Если делитель не равен квадратному корню num, добавьте к sum также результат деления num на делитель.
3⃣Проверка на совершенное число
Вычтите num из sum. Если результат равен num, вернуть true, иначе вернуть false.
😎 Решение:
class Solution {
public:
bool checkPerfectNumber(int num) {
if (num <= 0) return false;
int sum = 0;
for (int i = 1; i * i <= num; ++i) {
if (num % i == 0) {
sum += i;
if (i * i != num) {
sum += num / i;
}
}
}
return sum - num == num;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 715. Range Module
Сложность: hard
Модуль Range - это модуль, который отслеживает диапазоны чисел. Создайте структуру данных для отслеживания диапазонов, представленных в виде полуоткрытых интервалов, и запросов к ним. Полуоткрытый интервал [left, right) обозначает все вещественные числа x, где left <= x < right. Реализуйте класс RangeModule: RangeModule() Инициализирует объект структуры данных. void addRange(int left, int right) Добавляет полуоткрытый интервал [left, right), отслеживая каждое вещественное число в этом интервале. Добавление интервала, который частично перекрывает отслеживаемые в данный момент числа, должно добавить все числа в интервале [left, right), которые еще не отслеживаются. boolean queryRange(int left, int right) Возвращает true, если каждое действительное число в интервале [left, right) отслеживается в данный момент, и false в противном случае. void removeRange(int left, int right) Прекращает отслеживание каждого действительного числа, отслеживаемого в данный момент в полуоткрытом интервале [left, right).
Пример:
👨💻 Алгоритм:
1⃣Инициализируйте класс RangeModule с пустым списком диапазонов.
2⃣Для метода addRange(left, right) добавьте новый диапазон, объединяя его с существующими перекрывающимися диапазонами. Для метода queryRange(left, right) проверьте, полностью ли данный диапазон содержится в отслеживаемых диапазонах.
3⃣Для метода removeRange(left, right) удалите указанный диапазон, разбивая существующие диапазоны на соответствующие части.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Модуль Range - это модуль, который отслеживает диапазоны чисел. Создайте структуру данных для отслеживания диапазонов, представленных в виде полуоткрытых интервалов, и запросов к ним. Полуоткрытый интервал [left, right) обозначает все вещественные числа x, где left <= x < right. Реализуйте класс RangeModule: RangeModule() Инициализирует объект структуры данных. void addRange(int left, int right) Добавляет полуоткрытый интервал [left, right), отслеживая каждое вещественное число в этом интервале. Добавление интервала, который частично перекрывает отслеживаемые в данный момент числа, должно добавить все числа в интервале [left, right), которые еще не отслеживаются. boolean queryRange(int left, int right) Возвращает true, если каждое действительное число в интервале [left, right) отслеживается в данный момент, и false в противном случае. void removeRange(int left, int right) Прекращает отслеживание каждого действительного числа, отслеживаемого в данный момент в полуоткрытом интервале [left, right).
Пример:
Input
["RangeModule", "addRange", "removeRange", "queryRange", "queryRange", "queryRange"]
[[], [10, 20], [14, 16], [10, 14], [13, 15], [16, 17]]
Output
[null, null, null, true, false, true]
👨💻 Алгоритм:
1⃣Инициализируйте класс RangeModule с пустым списком диапазонов.
2⃣Для метода addRange(left, right) добавьте новый диапазон, объединяя его с существующими перекрывающимися диапазонами. Для метода queryRange(left, right) проверьте, полностью ли данный диапазон содержится в отслеживаемых диапазонах.
3⃣Для метода removeRange(left, right) удалите указанный диапазон, разбивая существующие диапазоны на соответствующие части.
😎 Решение:
class RangeModule {
public:
RangeModule() {}
void addRange(int left, int right) {
vector<pair<int, int>> newRanges;
int i = 0;
while (i < ranges.size() && ranges[i].second < left) {
newRanges.push_back(ranges[i]);
i++;
}
while (i < ranges.size() && ranges[i].first <= right) {
left = min(left, ranges[i].first);
right = max(right, ranges[i].second);
i++;
}
newRanges.push_back({left, right});
while (i < ranges.size()) {
newRanges.push_back(ranges[i]);
i++;
}
ranges = newRanges;
}
bool queryRange(int left, int right) {
for (auto& range : ranges) {
if (range.first <= left && right <= range.second) {
return true;
}
}
return false;
}
void removeRange(int left, int right) {
vector<pair<int, int>> newRanges;
for (auto& range : ranges) {
if (range.first < left) {
newRanges.push_back({range.first, min(range.second, left)});
}
if (right < range.second) {
newRanges.push_back({max(range.first, right), range.second});
}
}
ranges = newRanges;
}
private:
vector<pair<int, int>> ranges;
};Ставь 👍 и забирай 📚 Базу знаний
👍1
Задача: CodeTestcaseTest ResultTest Result1187. Make Array Strictly Increasing
Сложность: hard
Даны два целочисленных массива arr1 и arr2. Верните минимальное количество операций (возможно, ноль), необходимых для того, чтобы сделать arr1 строго возрастающим.
В одной операции вы можете выбрать два индекса 0 <= i < arr1.length и 0 <= j < arr2.length и выполнить присваивание arr1[i] = arr2[j].
Если нет способа сделать arr1 строго возрастающим, верните -1.
Пример:
👨💻 Алгоритм:
1⃣Сначала отсортируйте массив arr2 и инициализируйте хэш-таблицу dp для хранения промежуточных результатов. Определите функцию dfs(i, prev), которая вычисляет минимальное количество операций для сортировки массива arr1, начиная с индекса i, при условии, что предыдущий элемент равен prev. Если результат для (i, prev) уже существует в dp, то просто верните сохраненное значение.
2⃣Внутри функции dfs инициализируйте переменную cost значением float('inf'). Если arr1[i] больше, чем prev, обновите значение cost результатом вызова dfs(i + 1, arr1[i]). Используйте бинарный поиск, чтобы найти индекс idx наименьшего значения в arr2, которое больше prev. Если такой индекс существует, обновите значение cost результатом минимального значения между текущим значением cost и 1 + dfs(i + 1, arr2[idx]).
3⃣После всех вычислений обновите dp[(i, prev)] значением cost и верните cost. В конце вызовите dfs(0, -1) и верните его значение, если оно не равно float('inf'); в противном случае верните -1.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Даны два целочисленных массива arr1 и arr2. Верните минимальное количество операций (возможно, ноль), необходимых для того, чтобы сделать arr1 строго возрастающим.
В одной операции вы можете выбрать два индекса 0 <= i < arr1.length и 0 <= j < arr2.length и выполнить присваивание arr1[i] = arr2[j].
Если нет способа сделать arr1 строго возрастающим, верните -1.
Пример:
Input: arr1 = [1,5,3,6,7], arr2 = [1,3,2,4]
Output: 1
Explanation: Replace 5 with 2, then arr1 = [1, 2, 3, 6, 7].
👨💻 Алгоритм:
1⃣Сначала отсортируйте массив arr2 и инициализируйте хэш-таблицу dp для хранения промежуточных результатов. Определите функцию dfs(i, prev), которая вычисляет минимальное количество операций для сортировки массива arr1, начиная с индекса i, при условии, что предыдущий элемент равен prev. Если результат для (i, prev) уже существует в dp, то просто верните сохраненное значение.
2⃣Внутри функции dfs инициализируйте переменную cost значением float('inf'). Если arr1[i] больше, чем prev, обновите значение cost результатом вызова dfs(i + 1, arr1[i]). Используйте бинарный поиск, чтобы найти индекс idx наименьшего значения в arr2, которое больше prev. Если такой индекс существует, обновите значение cost результатом минимального значения между текущим значением cost и 1 + dfs(i + 1, arr2[idx]).
3⃣После всех вычислений обновите dp[(i, prev)] значением cost и верните cost. В конце вызовите dfs(0, -1) и верните его значение, если оно не равно float('inf'); в противном случае верните -1.
😎 Решение:
class Solution {
public:
int makeArrayIncreasing(vector<int>& arr1, vector<int>& arr2) {
sort(arr2.begin(), arr2.end());
int answer = dfs(0, -1, arr1, arr2);
return answer < 2001 ? answer : -1;
}
private:
unordered_map<pair<int, int>, int, hash_pair> dp;
int dfs(int i, int prev, vector<int>& arr1, vector<int>& arr2) {
if (i == arr1.size()) return 0;
pair<int, int> key = {i, prev};
if (dp.count(key)) return dp[key];
int cost = 2001;
if (arr1[i] > prev) {
cost = dfs(i + 1, arr1[i], arr1, arr2);
}
int idx = bisectRight(arr2, prev);
if (idx < arr2.size()) {
cost = min(cost, 1 + dfs(i + 1, arr2[idx], arr1, arr2));
}
dp[key] = cost;
return cost;
}
int bisectRight(const vector<int>& arr, int value) {
int left = 0, right = arr.size();
while (left < right) {
int mid = (left + right) / 2;
if (arr[mid] <= value) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
struct hash_pair {
template <class T1, class T2>
size_t operator()(const pair<T1, T2>& p) const {
auto hash1 = hash<T1>{}(p.first);
auto hash2 = hash<T2>{}(p.second);
return hash1 ^ hash2;
}
};
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 1133. Largest Unique Number
Сложность: easy
Вам Дан целочисленный массив nums, верните наибольшее целое число, которое встречается только один раз. Если ни одно целое число не встречается один раз, верните -1.
Пример:
👨💻 Алгоритм:
1⃣Создайте хеш-таблицу для хранения количества каждого числа в массиве.
2⃣Пройдите по массиву и заполните хеш-таблицу количеством каждого числа.
3⃣Инициализируйте результат значением -1. Пройдите по хеш-таблице и если значение ключа равно 1, установите результат равным максимальному значению между ключом и текущим результатом. Верните результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Вам Дан целочисленный массив nums, верните наибольшее целое число, которое встречается только один раз. Если ни одно целое число не встречается один раз, верните -1.
Пример:
Input: nums = [5,7,3,9,4,9,8,3,1]
Output: 8
Explanation: The maximum integer in the array is 9 but it is repeated. The number 8 occurs only once, so it is the answer.
👨💻 Алгоритм:
1⃣Создайте хеш-таблицу для хранения количества каждого числа в массиве.
2⃣Пройдите по массиву и заполните хеш-таблицу количеством каждого числа.
3⃣Инициализируйте результат значением -1. Пройдите по хеш-таблице и если значение ключа равно 1, установите результат равным максимальному значению между ключом и текущим результатом. Верните результат.
😎 Решение:
class Solution {
public:
int largestUniqueNumber(vector<int>& nums) {
unordered_map<int, int> count;
for (int num : nums) {
count[num]++;
}
int result = -1;
for (auto& entry : count) {
if (entry.second == 1) {
result = max(result, entry.first);
}
}
return result;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 1380. Lucky Numbers in a Matrix
Сложность: easy
Дана матрица m x n из различных чисел, верните все счастливые числа в матрице в любом порядке.
Счастливое число — это элемент матрицы, который является минимальным элементом в своей строке и максимальным в своем столбце.
Пример:
👨💻 Алгоритм:
1⃣Сохраните минимум каждой строки в список rowMin и максимум каждого столбца в список colMax.
2⃣Итерируйте по каждому числу в матрице и проверяйте, равно ли оно rowMin[i] и colMax[j].
3⃣Если число удовлетворяет условию, добавьте его в список luckyNumbers и верните luckyNumbers.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дана матрица m x n из различных чисел, верните все счастливые числа в матрице в любом порядке.
Счастливое число — это элемент матрицы, который является минимальным элементом в своей строке и максимальным в своем столбце.
Пример:
Input: matrix = [[3,7,8],[9,11,13],[15,16,17]]
Output: [15]
Explanation: 15 is the only lucky number since it is the minimum in its row and the maximum in its column.
👨💻 Алгоритм:
1⃣Сохраните минимум каждой строки в список rowMin и максимум каждого столбца в список colMax.
2⃣Итерируйте по каждому числу в матрице и проверяйте, равно ли оно rowMin[i] и colMax[j].
3⃣Если число удовлетворяет условию, добавьте его в список luckyNumbers и верните luckyNumbers.
😎 Решение:
class Solution {
public:
vector<int> luckyNumbers (vector<vector<int>>& matrix) {
int N = matrix.size(), M = matrix[0].size();
vector<int> rowMin;
for (int i = 0; i < N; i++) {
int rMin = INT_MAX;
for (int j = 0; j < M; j++) {
rMin = min(rMin, matrix[i][j]);
}
rowMin.push_back(rMin);
}
vector<int> colMax;
for (int i = 0; i < M; i++) {
int cMax = INT_MIN;
for (int j = 0; j < N; j++) {
cMax = max(cMax, matrix[j][i]);
}
colMax.push_back(cMax);
}
vector<int> luckyNumbers;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (matrix[i][j] == rowMin[i] && matrix[i][j] == colMax[j]) {
luckyNumbers.push_back(matrix[i][j]);
}
}
}
return luckyNumbers;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 748. Shortest Completing Word
Сложность: easy
Вам дан целочисленный массив nums, в котором наибольшее целое число уникально. Определите, является ли наибольший элемент массива по крайней мере в два раза больше всех остальных чисел в массиве. Если да, то верните индекс самого большого элемента, в противном случае верните -1.
Пример:
👨💻 Алгоритм:
1⃣Извлечь все буквы из licensePlate, игнорируя цифры и пробелы, и создать словарь для подсчета частоты каждой буквы.
2⃣Пройти по массиву words, проверяя каждое слово на соответствие требованиям.
3⃣Найти самое короткое завершающее слово среди подходящих.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Вам дан целочисленный массив nums, в котором наибольшее целое число уникально. Определите, является ли наибольший элемент массива по крайней мере в два раза больше всех остальных чисел в массиве. Если да, то верните индекс самого большого элемента, в противном случае верните -1.
Пример:
Input: licensePlate = "1s3 PSt", words = ["step","steps","stripe","stepple"]
Output: "steps"
👨💻 Алгоритм:
1⃣Извлечь все буквы из licensePlate, игнорируя цифры и пробелы, и создать словарь для подсчета частоты каждой буквы.
2⃣Пройти по массиву words, проверяя каждое слово на соответствие требованиям.
3⃣Найти самое короткое завершающее слово среди подходящих.
😎 Решение:
class Solution {
public:
string shortestCompletingWord(string licensePlate, vector<string>& words) {
unordered_map<char, int> licenseCount = getCharCount(licensePlate);
string result;
for (const string& word : words) {
if (isCompletingWord(word, licenseCount)) {
if (result.empty() || word.length() < result.length()) {
result = word;
}
}
}
return result;
}
private:
unordered_map<char, int> getCharCount(const string& s) {
unordered_map<char, int> count;
for (char c : s) {
if (isalpha(c)) {
count[tolower(c)]++;
}
}
return count;
}
bool isCompletingWord(const string& word, const unordered_map<char, int>& licenseCount) {
unordered_map<char, int> wordCount;
for (char c : word) {
wordCount[c]++;
}
for (const auto& entry : licenseCount) {
if (wordCount[entry.first] < entry.second) {
return false;
}
}
return true;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 1043. Partition Array for Maximum Sum
Сложность: medium
Если задан целочисленный массив arr, разбейте его на (смежные) подмассивы длины не более k. После разбиения значения каждого подмассива меняются так, чтобы стать максимальным значением этого подмассива. Верните наибольшую сумму заданного массива после разбиения. Тестовые примеры генерируются таким образом, чтобы ответ умещался в 32-битное целое число.
Пример:
👨💻 Алгоритм:
1⃣Инициализация:
Создаем массив dp, где dp[i] будет хранить наибольшую сумму подмассива, заканчивающегося в позиции i.
2⃣Заполнение массива dp:
Проходим по массиву arr и для каждой позиции i пытаемся разбить подмассив длины до k и обновить dp[i] с максимальной возможной суммой.
3⃣Поддержание максимального значения в подмассиве:
Для каждого подмассива длины 1 до k, вычисляем максимальное значение в этом подмассиве и обновляем dp[i].
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Если задан целочисленный массив arr, разбейте его на (смежные) подмассивы длины не более k. После разбиения значения каждого подмассива меняются так, чтобы стать максимальным значением этого подмассива. Верните наибольшую сумму заданного массива после разбиения. Тестовые примеры генерируются таким образом, чтобы ответ умещался в 32-битное целое число.
Пример:
Input: arr = [1,15,7,9,2,5,10], k = 3
Output: 84
👨💻 Алгоритм:
1⃣Инициализация:
Создаем массив dp, где dp[i] будет хранить наибольшую сумму подмассива, заканчивающегося в позиции i.
2⃣Заполнение массива dp:
Проходим по массиву arr и для каждой позиции i пытаемся разбить подмассив длины до k и обновить dp[i] с максимальной возможной суммой.
3⃣Поддержание максимального значения в подмассиве:
Для каждого подмассива длины 1 до k, вычисляем максимальное значение в этом подмассиве и обновляем dp[i].
😎 Решение:
class Solution {
public:
int maxSumAfterPartitioning(vector<int>& arr, int k) {
int n = arr.size();
vector<int> dp(n, 0);
for (int i = 0; i < n; ++i) {
int max_val = 0;
for (int j = 1; j <= k; ++j) {
if (i - j + 1 >= 0) {
max_val = max(max_val, arr[i - j + 1]);
if (i - j >= 0) {
dp[i] = max(dp[i], dp[i - j] + max_val * j);
} else {
dp[i] = max(dp[i], max_val * j);
}
}
}
}
return dp[n - 1];
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 201. Bitwise AND of Numbers Range
Сложность: medium
Даны два целых числа left и right, обозначающие диапазон [left, right].
Нужно вернуть результат побитового AND всех чисел в этом диапазоне (включительно).
Пример:
👨💻 Алгоритм:
1⃣Пока left < right, сдвигаем оба числа вправо (>>= 1), пока они не станут равны. Это находит общий префикс битов.
2⃣Подсчитываем количество сдвигов — это количество младших битов, которые могут изменяться в диапазоне, и обнуляются при AND.
3⃣После этого сдвигаем результат left обратно влево (<< shift) — возвращаем биты на место.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Даны два целых числа left и right, обозначающие диапазон [left, right].
Нужно вернуть результат побитового AND всех чисел в этом диапазоне (включительно).
Пример:
Input: left = 5, right = 7 Output: 4
👨💻 Алгоритм:
1⃣Пока left < right, сдвигаем оба числа вправо (>>= 1), пока они не станут равны. Это находит общий префикс битов.
2⃣Подсчитываем количество сдвигов — это количество младших битов, которые могут изменяться в диапазоне, и обнуляются при AND.
3⃣После этого сдвигаем результат left обратно влево (<< shift) — возвращаем биты на место.
😎 Решение:
class Solution {
public:
int rangeBitwiseAnd(int m, int n) {
int shift = 0;
while (m < n) {
m >>= 1;
n >>= 1;
++shift;
}
return m << shift;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 1269. Number of Ways to Stay in the Same Place After Some Steps
Сложность: hard
У вас есть указатель на индекс 0 в массиве размера arrLen. На каждом шаге вы можете перемещаться на 1 позицию влево, на 1 позицию вправо в массиве или оставаться на том же месте (указатель ни в коем случае не должен находиться за пределами массива). Учитывая два целых числа steps и arrLen, верните количество способов, при которых указатель все еще находится на индексе 0 после ровно шагов. Поскольку ответ может быть слишком большим, верните его по модулю 10^9 + 7.
Пример:
👨💻 Алгоритм:
1⃣Инициализируйте массив для хранения количества способов достижения каждого индекса на каждом шаге.
2⃣Используйте динамическое программирование для подсчета количества способов достижения каждого индекса на каждом шаге.
3⃣Используйте динамическое программирование для подсчета количества способов достижения каждого индекса на каждом шаге.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
У вас есть указатель на индекс 0 в массиве размера arrLen. На каждом шаге вы можете перемещаться на 1 позицию влево, на 1 позицию вправо в массиве или оставаться на том же месте (указатель ни в коем случае не должен находиться за пределами массива). Учитывая два целых числа steps и arrLen, верните количество способов, при которых указатель все еще находится на индексе 0 после ровно шагов. Поскольку ответ может быть слишком большим, верните его по модулю 10^9 + 7.
Пример:
Input: steps = 3, arrLen = 2
Output: 4
👨💻 Алгоритм:
1⃣Инициализируйте массив для хранения количества способов достижения каждого индекса на каждом шаге.
2⃣Используйте динамическое программирование для подсчета количества способов достижения каждого индекса на каждом шаге.
3⃣Используйте динамическое программирование для подсчета количества способов достижения каждого индекса на каждом шаге.
😎 Решение:
class Solution {
public:
int numWays(int steps, int arrLen) {
const int mod = 1e9 + 7;
int max_pos = min(arrLen - 1, steps);
vector<int> dp(max_pos + 1, 0);
dp[0] = 1;
for (int step = 0; step < steps; ++step) {
vector<int> new_dp(max_pos + 1, 0);
for (int i = 0; i <= max_pos; ++i) {
new_dp[i] = dp[i] % mod;
if (i > 0) new_dp[i] = (new_dp[i] + dp[i - 1]) % mod;
if (i < max_pos) new_dp[i] = (new_dp[i] + dp[i + 1]) % mod;
}
dp = new_dp;
}
return dp[0];
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 1271. Hexspeak
Сложность: easy
Десятичное число можно преобразовать в его шестнадцатеричное представление, сначала преобразовав его в прописную шестнадцатеричную строку, а затем заменив все вхождения цифры '0' на букву 'O', а цифры '1' - на букву 'I'. Такое представление допустимо тогда и только тогда, когда оно состоит только из букв набора {'A', 'B', 'C', 'D', 'E', 'F', 'I', 'O'}. Получив строку num, представляющую десятичное целое число n, верните шестнадцатеричное представление n, если оно допустимо, иначе верните "ERROR".
Пример:
👨💻 Алгоритм:
1⃣Преобразуйте десятичное число в шестнадцатеричную строку в верхнем регистре.
2⃣Замените все вхождения цифры '0' на букву 'O', а цифры '1' на букву 'I'
3⃣Проверьте, что преобразованная строка содержит только допустимые символы. Если это так, верните строку, иначе верните "ERROR".
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Десятичное число можно преобразовать в его шестнадцатеричное представление, сначала преобразовав его в прописную шестнадцатеричную строку, а затем заменив все вхождения цифры '0' на букву 'O', а цифры '1' - на букву 'I'. Такое представление допустимо тогда и только тогда, когда оно состоит только из букв набора {'A', 'B', 'C', 'D', 'E', 'F', 'I', 'O'}. Получив строку num, представляющую десятичное целое число n, верните шестнадцатеричное представление n, если оно допустимо, иначе верните "ERROR".
Пример:
Input: num = "257"
Output: "IOI"
👨💻 Алгоритм:
1⃣Преобразуйте десятичное число в шестнадцатеричную строку в верхнем регистре.
2⃣Замените все вхождения цифры '0' на букву 'O', а цифры '1' на букву 'I'
3⃣Проверьте, что преобразованная строка содержит только допустимые символы. Если это так, верните строку, иначе верните "ERROR".
😎 Решение:
class Solution {
public:
string toHexString(string num) {
stringstream ss;
ss << hex << uppercase << stol(num);
string hexStr = ss.str();
for (char& c : hexStr) {
if (c == '0') c = 'O';
else if (c == '1') c = 'I';
else if (string("ABCDEFIO").find(c) == string::npos) return "ERROR";
}
return hexStr;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 1370. Increasing Decreasing String
Сложность: easy
Дана строка s. Переставьте символы строки, используя следующий алгоритм:
Выберите наименьший символ из s и добавьте его к результату.
Выберите наименьший символ из s, который больше последнего добавленного символа, и добавьте его.
Повторяйте шаг 2, пока не сможете выбрать больше символов.
Выберите наибольший символ из s и добавьте его к результату.
Выберите наибольший символ из s, который меньше последнего добавленного символа, и добавьте его.
Повторяйте шаг 5, пока не сможете выбрать больше символов.
Повторяйте шаги с 1 по 6, пока не выберете все символы из s.
На каждом этапе, если наименьший или наибольший символ появляется более одного раза, вы можете выбрать любое его вхождение и добавить его к результату.
Верните результирующую строку после сортировки s с помощью этого алгоритма.
Пример:
👨💻 Алгоритм:
1⃣Инициализация и сортировка:
Создайте словарь для подсчета количества каждого символа в строке s. Создайте результирующую строку result.
2⃣Перебор и добавление символов:
Используйте два цикла: первый для добавления символов в возрастающем порядке, второй — в убывающем. В каждом цикле добавляйте символы к результату, обновляя их количество в словаре.
3⃣Проверка завершения:
Повторяйте шаги 2 и 3, пока не будут добавлены все символы из строки s в result.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дана строка s. Переставьте символы строки, используя следующий алгоритм:
Выберите наименьший символ из s и добавьте его к результату.
Выберите наименьший символ из s, который больше последнего добавленного символа, и добавьте его.
Повторяйте шаг 2, пока не сможете выбрать больше символов.
Выберите наибольший символ из s и добавьте его к результату.
Выберите наибольший символ из s, который меньше последнего добавленного символа, и добавьте его.
Повторяйте шаг 5, пока не сможете выбрать больше символов.
Повторяйте шаги с 1 по 6, пока не выберете все символы из s.
На каждом этапе, если наименьший или наибольший символ появляется более одного раза, вы можете выбрать любое его вхождение и добавить его к результату.
Верните результирующую строку после сортировки s с помощью этого алгоритма.
Пример:
Input: s = "rat"
Output: "art"
Explanation: The word "rat" becomes "art" after re-ordering it with the mentioned algorithm.
👨💻 Алгоритм:
1⃣Инициализация и сортировка:
Создайте словарь для подсчета количества каждого символа в строке s. Создайте результирующую строку result.
2⃣Перебор и добавление символов:
Используйте два цикла: первый для добавления символов в возрастающем порядке, второй — в убывающем. В каждом цикле добавляйте символы к результату, обновляя их количество в словаре.
3⃣Проверка завершения:
Повторяйте шаги 2 и 3, пока не будут добавлены все символы из строки s в result.
😎 Решение:
#include <string>
#include <vector>
class Solution {
public:
std::string sortString(std::string s) {
std::vector<int> charCount(26, 0);
for (char c : s) {
charCount[c - 'a']++;
}
std::string result;
while (result.size() < s.size()) {
for (char c = 'a'; c <= 'z'; c++) {
if (charCount[c - 'a'] > 0) {
result += c;
charCount[c - 'a']--;
}
}
for (char c = 'z'; c >= 'a'; c--) {
if (charCount[c - 'a'] > 0) {
result += c;
charCount[c - 'a']--;
}
}
}
return result;
}
};
Ставь 👍 и забирай 📚 Базу знаний
Задача: 1256. Encode Number
Сложность: medium
Даны список слов, список отдельных букв (могут повторяться) и оценка каждого символа. Верните максимальную оценку любого правильного набора слов, образованного с помощью заданных букв (words[i] не может быть использовано два или более раз). Не обязательно использовать все символы в буквах, каждая буква может быть использована только один раз. Оценка букв 'a', 'b', 'c', ... , 'z' задаются значениями score[0], score[1], ... , score[25] соответственно.
Пример:
👨💻 Алгоритм:
1⃣На основе предоставленной таблицы можно выявить закономерность для преобразования целого числа n в строку f(n)
2⃣Из таблицы видно, что последовательность строк соответствует последовательности чисел в двоичной системе счисления за исключением начального значения n = 0.
3⃣Таким образом, можно вывести, что:
Для каждого значения n > 0, функция f(n) представляет собой двоичное представление числа (n - 1).
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Даны список слов, список отдельных букв (могут повторяться) и оценка каждого символа. Верните максимальную оценку любого правильного набора слов, образованного с помощью заданных букв (words[i] не может быть использовано два или более раз). Не обязательно использовать все символы в буквах, каждая буква может быть использована только один раз. Оценка букв 'a', 'b', 'c', ... , 'z' задаются значениями score[0], score[1], ... , score[25] соответственно.
Пример:
Input: num = 23
Output: "1000"
👨💻 Алгоритм:
1⃣На основе предоставленной таблицы можно выявить закономерность для преобразования целого числа n в строку f(n)
2⃣Из таблицы видно, что последовательность строк соответствует последовательности чисел в двоичной системе счисления за исключением начального значения n = 0.
3⃣Таким образом, можно вывести, что:
Для каждого значения n > 0, функция f(n) представляет собой двоичное представление числа (n - 1).
😎 Решение:
class Solution {
public:
string encode(int num) {
if (num == 0) return "";
string binary = "";
num -= 1;
while (num > 0) {
binary = (num % 2 == 0 ? "0" : "1") + binary;
num /= 2;
}
return binary;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 340. Longest Substring with At Most K Distinct Characters
Сложность: medium
Дана строка s и целое число k. Верните длину самой длинной подстроки s, которая содержит не более k различных символов.
Пример:
👨💻 Алгоритм:
1⃣Инициализация
Используйте два указателя (left и right) для отслеживания текущего окна в строке. Создайте словарь для отслеживания количества каждого символа в текущем окне. Инициализируйте переменные для хранения максимальной длины подстроки (max_length).
2⃣Раздвижение окна
Перемещайте правый указатель (right) по строке и обновляйте словарь. Если количество различных символов в словаре превышает k, перемещайте левый указатель (left) вправо, уменьшая счетчик символов, пока количество различных символов снова не станет меньше или равно k.
3⃣Обновление максимальной длины
На каждом шаге проверяйте и обновляйте максимальную длину подстроки, если текущее окно содержит не более k различных символов. В конце верните максимальную длину подстроки.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дана строка s и целое число k. Верните длину самой длинной подстроки s, которая содержит не более k различных символов.
Пример:
Input: n = 27
Output: true
Explanation: 27 = 3^3
👨💻 Алгоритм:
1⃣Инициализация
Используйте два указателя (left и right) для отслеживания текущего окна в строке. Создайте словарь для отслеживания количества каждого символа в текущем окне. Инициализируйте переменные для хранения максимальной длины подстроки (max_length).
2⃣Раздвижение окна
Перемещайте правый указатель (right) по строке и обновляйте словарь. Если количество различных символов в словаре превышает k, перемещайте левый указатель (left) вправо, уменьшая счетчик символов, пока количество различных символов снова не станет меньше или равно k.
3⃣Обновление максимальной длины
На каждом шаге проверяйте и обновляйте максимальную длину подстроки, если текущее окно содержит не более k различных символов. В конце верните максимальную длину подстроки.
😎 Решение:
class Solution {
public:
int lengthOfLongestSubstringKDistinct(string s, int k) {
int left = 0, right = 0;
unordered_map<char, int> charCount;
int maxLength = 0;
while (right < s.length()) {
charCount[s[right]]++;
while (charCount.size() > k) {
charCount[s[left]]--;
if (charCount[s[left]] == 0) {
charCount.erase(s[left]);
}
left++;
}
maxLength = max(maxLength, right - left + 1);
right++;
}
return maxLength;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 987. Vertical Order Traversal of a Binary Tree
Сложность: medium
Вам даны два списка закрытых интервалов, firstList и secondList, где firstList[i] = [starti, endi] и secondList[j] = [startj, endj]. Каждый список интервалов является попарно непересекающимся и отсортированным.
Верните пересечение этих двух списков интервалов.
Закрытый интервал [a, b] (где a <= b) обозначает множество действительных чисел x с a <= x <= b.
Пересечение двух закрытых интервалов - это множество действительных чисел, которые либо пусты, либо представлены как закрытый интервал. Например, пересечение [1, 3] и [2, 4] равно [2, 3].
Пример:
👨💻 Алгоритм:
1⃣Инициализация указателей:
Создать словарь для хранения узлов по их координатам (col, row).
Создать очередь для обхода в ширину (BFS), содержащую начальную пару (root, (0, 0)).
2⃣Поиск пересечений:
Выполнить BFS обход дерева. Для каждого узла сохранить его значение в словаре по ключу (col, row).
Добавить левый потомок в очередь с координатами (row + 1, col - 1).
Добавить правый потомок в очередь с координатами (row + 1, col + 1).
3⃣Возврат результата:
Отсортировать ключи словаря по col и затем по row.
Для каждого столбца, упорядочить узлы по row и значениям, и добавить их в результирующий список.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам даны два списка закрытых интервалов, firstList и secondList, где firstList[i] = [starti, endi] и secondList[j] = [startj, endj]. Каждый список интервалов является попарно непересекающимся и отсортированным.
Верните пересечение этих двух списков интервалов.
Закрытый интервал [a, b] (где a <= b) обозначает множество действительных чисел x с a <= x <= b.
Пересечение двух закрытых интервалов - это множество действительных чисел, которые либо пусты, либо представлены как закрытый интервал. Например, пересечение [1, 3] и [2, 4] равно [2, 3].
Пример:
Input: root = [3,9,20,null,null,15,7]
Output: [[9],[3,15],[20],[7]]
👨💻 Алгоритм:
1⃣Инициализация указателей:
Создать словарь для хранения узлов по их координатам (col, row).
Создать очередь для обхода в ширину (BFS), содержащую начальную пару (root, (0, 0)).
2⃣Поиск пересечений:
Выполнить BFS обход дерева. Для каждого узла сохранить его значение в словаре по ключу (col, row).
Добавить левый потомок в очередь с координатами (row + 1, col - 1).
Добавить правый потомок в очередь с координатами (row + 1, col + 1).
3⃣Возврат результата:
Отсортировать ключи словаря по col и затем по row.
Для каждого столбца, упорядочить узлы по row и значениям, и добавить их в результирующий список.
😎 Решение:
class Solution {
public:
vector<vector<int>> verticalTraversal(TreeNode* root) {
map<int, vector<pair<int, int>>> colTable;
queue<pair<TreeNode*, pair<int, int>>> queue;
queue.push({root, {0, 0}});
while (!queue.empty()) {
auto [node, pos] = queue.front();
queue.pop();
int row = pos.first, col = pos.second;
colTable[col].emplace_back(row, node->val);
if (node->left) {
queue.push({node->left, {row + 1, col - 1}});
}
if (node->right) {
queue.push({node->right, {row + 1, col + 1}});
}
}
vector<vector<int>> result;
for (auto& [col, pairs] : colTable) {
sort(pairs.begin(), pairs.end());
vector<int> sortedCol;
for (auto& [row, val] : pairs) {
sortedCol.push_back(val);
}
result.push_back(sortedCol);
}
return result;
}
};Ставь 👍 и забирай 📚 Базу знаний
Задача: 320. Generalized Abbreviation
Сложность: medium
Обобщенная аббревиатура слова может быть построена путем замены любых неперекрывающихся и несмежных подстрок на их соответствующие длины.
Например, "abcde" можно сократить следующим образом:
"a3e" ("bcd" заменено на "3")
"1bcd1" ("a" и "e" заменены на "1")
"5" ("abcde" заменено на "5")
"abcde" (без замены подстрок)
Однако следующие аббревиатуры недействительны:
"23" ("ab" заменено на "2" и "cde" заменено на "3") недействительно, так как выбранные подстроки смежные.
"22de" ("ab" заменено на "2" и "bc" заменено на "2") недействительно, так как выбранные подстроки перекрываются.
Дано слово word, верните список всех возможных обобщенных аббревиатур слова. Верните ответ в любом порядке.
Пример:
👨💻 Алгоритм:
1⃣Создание битовых масок
Каждая аббревиатура имеет одно к одному соответствие с n-битным двоичным числом x, где n - длина слова. Используйте эти числа в качестве чертежей для построения соответствующих аббревиатур.
2⃣Генерация аббревиатур
Для числа x просканируйте его бит за битом, чтобы определить, какие символы следует сохранить, а какие - сократить. Если бит равен 1, сохраните соответствующий символ, если 0 - замените его на счетчик.
3⃣Перебор всех комбинаций
Для каждого числа от 0 до 2^n - 1 используйте его битовое представление для создания соответствующей аббревиатуры. Сканируйте число x побитово, извлекая его последний бит с помощью b = x & 1 и сдвигая x вправо на один бит x >>= 1.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Обобщенная аббревиатура слова может быть построена путем замены любых неперекрывающихся и несмежных подстрок на их соответствующие длины.
Например, "abcde" можно сократить следующим образом:
"a3e" ("bcd" заменено на "3")
"1bcd1" ("a" и "e" заменены на "1")
"5" ("abcde" заменено на "5")
"abcde" (без замены подстрок)
Однако следующие аббревиатуры недействительны:
"23" ("ab" заменено на "2" и "cde" заменено на "3") недействительно, так как выбранные подстроки смежные.
"22de" ("ab" заменено на "2" и "bc" заменено на "2") недействительно, так как выбранные подстроки перекрываются.
Дано слово word, верните список всех возможных обобщенных аббревиатур слова. Верните ответ в любом порядке.
Пример:
Input: word = "a"
Output: ["1","a"]
👨💻 Алгоритм:
1⃣Создание битовых масок
Каждая аббревиатура имеет одно к одному соответствие с n-битным двоичным числом x, где n - длина слова. Используйте эти числа в качестве чертежей для построения соответствующих аббревиатур.
2⃣Генерация аббревиатур
Для числа x просканируйте его бит за битом, чтобы определить, какие символы следует сохранить, а какие - сократить. Если бит равен 1, сохраните соответствующий символ, если 0 - замените его на счетчик.
3⃣Перебор всех комбинаций
Для каждого числа от 0 до 2^n - 1 используйте его битовое представление для создания соответствующей аббревиатуры. Сканируйте число x побитово, извлекая его последний бит с помощью b = x & 1 и сдвигая x вправо на один бит x >>= 1.
😎 Решение:
class Solution {
public:
vector<string> generateAbbreviations(string word) {
vector<string> ans;
for (int x = 0; x < (1 << word.length()); ++x)
ans.push_back(abbr(word, x));
return ans;
}
private:
string abbr(const string& word, int x) {
string builder;
int k = 0, n = word.length();
for (int i = 0; i < n; ++i, x >>= 1) {
if ((x & 1) == 0) {
if (k != 0) {
builder += to_string(k);
k = 0;
}
builder += word[i];
} else {
++k;
}
}
if (k != 0) builder += to_string(k);
return builder;
}
};Ставь 👍 и забирай 📚 Базу знаний