uk
Feedback
C/C++ | LeetCode

C/C++ | LeetCode

Відкрити в Telegram

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv

Показати більше
3 239
Підписники
-124 години
-27 днів
+1230 день

Триває завантаження даних...

Залучення підписників
серпень '26
серпень '26
+26
в 0 каналах
липень '26
+42
в 0 каналах
Get PRO
червень '26
+30
в 1 каналах
Get PRO
травень '26
+35
в 0 каналах
Get PRO
квітень '26
+35
в 0 каналах
Get PRO
березень '26
+32
в 0 каналах
Get PRO
лютий '26
+45
в 0 каналах
Get PRO
січень '26
+35
в 0 каналах
Get PRO
грудень '25
+37
в 0 каналах
Get PRO
листопад '25
+84
в 0 каналах
Get PRO
жовтень '25
+43
в 0 каналах
Get PRO
вересень '25
+35
в 0 каналах
Get PRO
серпень '25
+40
в 0 каналах
Get PRO
липень '25
+40
в 1 каналах
Get PRO
червень '25
+43
в 0 каналах
Get PRO
травень '25
+44
в 0 каналах
Get PRO
квітень '25
+61
в 0 каналах
Get PRO
березень '25
+60
в 1 каналах
Get PRO
лютий '25
+179
в 3 каналах
Get PRO
січень '25
+79
в 53 каналах
Get PRO
грудень '24
+64
в 0 каналах
Get PRO
листопад '24
+91
в 1 каналах
Get PRO
жовтень '24
+424
в 13 каналах
Get PRO
вересень '24
+1 488
в 331 каналах
Get PRO
серпень '24
+91
в 0 каналах
Get PRO
липень '24
+826
в 219 каналах
Get PRO
червень '24
+1 211
в 232 каналах
Дата
Залучення підписників
Згадування
Канали
26 серпня+1
25 серпня+1
24 серпня+1
23 серпня+2
22 серпня+1
21 серпня0
20 серпня+1
19 серпня0
18 серпня+1
17 серпня+3
16 серпня+2
15 серпня0
14 серпня+1
13 серпня0
12 серпня+1
11 серпня+1
10 серпня+3
09 серпня+2
08 серпня+1
07 серпня0
06 серпня+2
05 серпня+1
04 серпня0
03 серпня0
02 серпня+1
01 серпня0
Дописи каналу
Задача: 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, если целевое значение существует в восстановленном двоичном дереве. Пример:
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();
    }
};
Ставь 👍 и забирай 📚 Базу знаний

2
Задача: 1026. Maximum Difference Between Node and Ancestor Сложность: 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); } }; Ставь 👍 и забирай 📚 Базу знаний
122
3
Пожизненный PRO доступ на easyoffer — по цене одного года! До 2 сентября вы можете купить PRO навсегда. Покупаешь один раз — пользуешься всю жизнь. – База вопросов и задач из собеседований – Примеры видео-ответов на вопросы – Записи реальных собеседований – Тренажеры "Проработка вопросов" и "Реальное собеседование" – Аналитика требований из вакансий – Автоотклики на вакансии – Агрегатор вакансий (скоро) 👉 Купить PRO со скидкой 70%: https://easyoffer.ru/pro
161
4
Задача: 16. 3Sum Closest Сложность: 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; } }; Ставь 👍 и забирай 📚 Базу знаний
160
5
Задача: 859. Buddy Strings Сложность: 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]; } }; Ставь 👍 и забирай 📚 Базу знаний
154
6
Задача: 1214. Two Sum BSTs Сложность: 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; } }; Ставь 👍 и забирай 📚 Базу знаний
168
7
Задача: 760. Find Anagram Mappings Сложность: easy Вам даны два целочисленных массива nums1 и nums2, где nums2 - анаграмма nums1. Оба массива могут содержать дубликаты. Верните индексное отображение массива mapping из nums1 в nums2, где mapping[i] = j означает, что i-й элемент в nums1 появляется в nums2 по индексу j. Если ответов несколько, верните любой из них. Массив a является анаграммой массива b означает, что b создается путем случайного изменения порядка элементов в a. Пример: Input: nums1 = [12,28,46,32,50], nums2 = [50,12,32,46,28] Output: [1,4,3,2,0] 👨‍💻 Алгоритм: 1⃣Создайте словарь для хранения индексов элементов в nums2. 2⃣Пройдите по элементам массива nums1 и для каждого элемента найдите соответствующий индекс в nums2, используя словарь. 3⃣Верните массив индексов. 😎 Решение: vector<int> anagramMapping(vector<int>& nums1, vector<int>& nums2) { unordered_map<int, vector<int>> indexMap; for (int i = 0; i < nums2.size(); i++) { indexMap[nums2[i]].push_back(i); } vector<int> mapping; for (int num : nums1) { mapping.push_back(indexMap[num].back()); indexMap[num].pop_back(); } return mapping; } Ставь 👍 и забирай 📚 Базу знаний
180
8
Задача: 1284. Minimum Number of Flips to Convert Binary Matrix to Zero Matrix Сложность: hard Дана бинарная матрица mat размером m x n. За один шаг вы можете выбрать одну ячейку и перевернуть её и всех её четырех соседей, если они существуют (Перевернуть означает изменить 1 на 0 и 0 на 1). Пара ячеек называется соседями, если они имеют общую границу. Верните минимальное количество шагов, необходимых для преобразования матрицы mat в нулевую матрицу или -1, если это невозможно. Бинарная матрица - это матрица, в которой все ячейки равны 0 или 1. Нулевая матрица - это матрица, в которой все ячейки равны 0. Пример: Input: mat = [[0,0],[0,1]] Output: 3 Explanation: One possible solution is to flip (1, 0) then (0, 1) and finally (1, 1) as shown. 👨‍💻 Алгоритм: 1⃣Переберите все возможные варианты решений для первой строки матрицы. Каждое решение представляется массивом, где каждый элемент равен 0 или 1, указывая, перевернут ли соответствующий элемент в первой строке. Инициализируйте два бинарных массива для каждой строки: lastState[], содержащий значения предыдущей строки, и changed[], представляющий, были ли значения в текущей строке перевернуты при работе с предыдущей строкой. 2⃣Для каждой строки в матрице используйте следующий шаг для вычисления состояния, инициализированного как changed: Для каждой позиции j в диапазоне [0, n - 1] текущей строки измените значение state[j] соответственно, если lastState[j] равно 1. Переверните state[j], state[j - 1] и state[j + 1], если они существуют. Увеличьте счетчик переворотов на 1. Значения, которые будут перевернуты в следующей строке, точно равны lastState, а решение для следующей строки точно равно массиву state. Поэтому установите changed = lastState и lastState = state, затем переходите к следующей строке. 3⃣После обработки всех строк проверьте, содержит ли lastState все нули, чтобы определить, является ли это допустимым решением. Верните минимальное количество переворотов для всех допустимых решений. 😎 Решение: class Solution { int better(int x, int y) { return x < 0 || (y >= 0 && y < x) ? y : x; } int dfs(const vector<vector<int>>& mat, vector<int>& operations) { if (operations.size() == mat[0].size()) { vector<int> changed(mat[0].size()); vector<int> last_state = operations; int maybe = 0; for (const vector<int>& row : mat) { vector<int> state = changed; for (int j = 0; j < row.size(); ++j) { state[j] ^= row[j]; if (last_state[j]) { state[j] ^= 1; if (j) { state[j - 1] ^= 1; } if (j + 1 < row.size()) { state[j + 1] ^= 1; } ++maybe; } } changed = last_state; last_state = state; } for (int x : last_state) { if (x) { return -1; } } return maybe; } operations.push_back(0); const int maybe1 = dfs(mat, operations); operations.back() = 1; const int maybe2 = dfs(mat, operations); operations.pop_back(); return better(maybe1, maybe2); } public: int minFlips(vector<vector<int>>& mat) { vector<int> operations; return dfs(mat, operations); } }; Ставь 👍 и забирай 📚 Базу знаний
161
9
Задача: 325. Maximum Size Subarray Sum Equals k Сложность: medium Дан целочисленный массив nums и целое число k. Верните максимальную длину подмассива, сумма которого равна k. Если такого подмассива не существует, верните 0. Пример: Input: nums = [1,-1,5,-2,3], k = 3 Output: 4 Explanation: The subarray [1, -1, 5, -2] sums to 3 and is the longest. 👨‍💻 Алгоритм: 1⃣Инициализация переменных Инициализируйте prefixSum как 0 для отслеживания префиксной суммы nums. Инициализируйте longestSubarray как 0 для отслеживания самой длинной подмассы с суммой k. Инициализируйте хеш-карту indices для хранения префиксных сумм и их индексов. 2⃣Итерация по массиву На каждом индексе i, добавляйте nums[i] к prefixSum. Проверьте следующие условия: Если prefixSum == k, обновите longestSubarray как i + 1. Если prefixSum - k существует в indices, обновите longestSubarray, если текущая длина подмассива больше. Если текущий prefixSum еще не существует в indices, добавьте indices[prefixSum] = i. 3⃣Возврат результата Верните значение longestSubarray. 😎 Решение: #include <vector> #include <unordered_map> class Solution { public: int maxSubArrayLen(std::vector<int>& nums, int k) { int prefixSum = 0; int longestSubarray = 0; std::unordered_map<int, int> indices; for (int i = 0; i < nums.size(); ++i) { prefixSum += nums[i]; if (prefixSum == k) { longestSubarray = i + 1; } if (indices.find(prefixSum - k) != indices.end()) { longestSubarray = std::max(longestSubarray, i - indices[prefixSum - k]); } if (indices.find(prefixSum) == indices.end()) { indices[prefixSum] = i; } } return longestSubarray; } }; Ставь 👍 и забирай 📚 Базу знаний
180
10
Задача: 1199. Minimum Time to Build Blocks Сложность: hard Вам дан список блоков, где blocks[i] = t означает, что на строительство i-го блока требуется t единиц времени. Блок может быть построен только одним рабочим. Рабочий может либо разделиться на двух рабочих (количество рабочих увеличивается на одного), либо построить блок и уйти домой. Оба решения требуют некоторого времени. Время, затраченное на разделение одного рабочего на двух, задано целым числом split. Обратите внимание, что если два рабочих разделяются одновременно, они разделяются параллельно, поэтому затраты времени будут равны split. Выведите минимальное время, необходимое для строительства всех блоков. Изначально есть только один рабочий. Пример: Input: blocks = [1,2,3], split = 1 Output: 4 Explanation: Split 1 worker into 2, then assign the first worker to the last block and split the second worker into 2. Then, use the two unassigned workers to build the first two blocks. The cost is 1 + max(3, 1 + max(1, 2)) = 4. 👨‍💻 Алгоритм: 1⃣Подготовка кучи строительного времени: Инициализируйте кучу строительного времени, изначально содержащую все значения времени из массива blocks. 2⃣Обработка кучи: Пока в куче больше одного элемента: - извлеките минимальное значение из кучи, обозначим его как x. - извлеките следующее минимальное значение из кучи, обозначим его как y. - создайте новое время строительства, которое равно split + y, и вставьте его обратно в кучу. 3⃣Возврат результата: Когда в куче останется только одно значение, оно и будет минимальным временем, необходимым для строительства всех блоков. 😎 Решение: #include <vector> #include <queue> class Solution { public: int minBuildTime(std::vector<int>& blocks, int split) { std::priority_queue<int, std::vector<int>, std::greater<int>> pq(blocks.begin(), blocks.end()); while (pq.size() > 1) { int x = pq.top(); pq.pop(); int y = pq.top(); pq.pop(); pq.push(split + y); } return pq.top(); } }; Ставь 👍 и забирай 📚 Базу знаний
200
11
Задача: 210. Course Schedule II Сложность: medium Дано число numCourses и список пар prerequisites, где каждая пара [a, b] означает: чтобы взять курс a, нужно сначала пройти курс b. Верните один из возможных порядков прохождения курсов. Если пройти все курсы невозможно (из-за циклов) — верните пустой массив. Пример: Input: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] Output: [0,2,1,3] 👨‍💻 Алгоритм: 1⃣Построение графа и подготовка к DFS Создаем список смежности adjList, где adjList[b] содержит все курсы, зависящие от b. Каждый курс помечаем цветом: WHITE = 1 — не посещён GRAY = 2 — в процессе обработки BLACK = 3 — полностью обработан 2⃣Обход в глубину (DFS) и детектирование цикла Для каждого непосещённого узла запускаем dfs. Если во время обхода обнаруживаем цикл (возврат к GRAY узлу), значит, пройти курсы невозможно. 3⃣Формирование ответа После завершения DFS по всем узлам формируем порядок курсов из стека (или массива) topologicalOrder, инвертируя его. 😎Решение: cppКопироватьРедактироватьclass Solution { public: int WHITE = 1; int GRAY = 2; int BLACK = 3; vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) { bool isPossible = true; map<int, int> color; map<int, vector<int>> adjList; vector<int> topologicalOrder; for (int i = 0; i < numCourses; i++) color[i] = WHITE; for (vector<int> relation : prerequisites) { int dest = relation[0]; int src = relation[1]; adjList[src].push_back(dest); } for (int i = 0; i < numCourses && isPossible; i++) { if (color[i] == WHITE) { dfs(i, color, adjList, isPossible, topologicalOrder); } } vector<int> order; if (isPossible) { order.resize(numCourses); for (int i = 0; i < numCourses; i++) { order[i] = topologicalOrder[numCourses - i - 1]; } } return order; } void dfs(int node, map<int, int>& color, map<int, vector<int>>& adjList, bool& isPossible, vector<int>& topologicalOrder) { if (!isPossible) return; color[node] = GRAY; for (int neighbor : adjList[node]) { if (color[neighbor] == WHITE) { dfs(neighbor, color, adjList, isPossible, topologicalOrder); } else if (color[neighbor] == GRAY) { isPossible = false; } } color[node] = BLACK; topologicalOrder.push_back(node); } }; Ставь 👍 и забирай 📚 Базу знаний
195
12
Задача: 1217. Minimum Cost to Move Chips to The Same Position Сложность: easy У нас есть n фишек, где позиция i-й фишки равна position[i]. Нам нужно переместить все фишки в одну и ту же позицию. За один шаг мы можем изменить позицию i-й фишки с position[i] на: position[i] + 2 или position[i] - 2 с затратами = 0. position[i] + 1 или position[i] - 1 с затратами = 1. Верните минимальные затраты, необходимые для перемещения всех фишек в одну и ту же позицию. Пример: Input: position = [2,2,2,3,3] Output: 2 Explanation: We can move the two chips at position 3 to position 2. Each move has cost = 1. The total cost = 2. 👨‍💻 Алгоритм: 1⃣Посчитать количество фишек на четных и нечетных позициях. 2⃣Сравнить количество фишек на четных и нечетных позициях. 3⃣Вернуть минимальное количество фишек как минимальную стоимость для перемещения всех фишек в одну позицию. 😎 Решение: class Solution { public: int minCostToMoveChips(vector<int>& position) { int evenCount = 0; int oddCount = 0; for (int pos : position) { if (pos % 2 == 0) { evenCount++; } else { oddCount++; } } return min(evenCount, oddCount); } }; Ставь 👍 и забирай 📚 Базу знаний
187
13
Задача: 1434. Number of Ways to Wear Different Hats to Each Other Сложность: hard Дано n человек и 40 видов шляп, пронумерованных от 1 до 40. Дан двумерный целочисленный массив hats, где hats[i] — список всех шляп, предпочитаемых i-м человеком. Вернуть количество способов, которыми n человек могут носить различные шляпы друг у друга. Поскольку ответ может быть слишком большим, вернуть его по модулю 10^9 + 7. Пример: Input: hats = [[3,4],[4,5],[5]] Output: 1 Explanation: There is only one way to choose hats given the conditions. First person choose hat 3, Second person choose hat 4 and last one hat 5. 👨‍💻 Алгоритм: 1⃣Инициализировать переменные: n - количество людей, done = 2^n - 1, MOD = 10^9 + 7, memo - двумерный массив размером 41 * done, заполненный -1, и hatsToPeople - отображение шляп на людей. 2⃣Заполнить hatsToPeople, сопоставив каждую шляпу людям, которые её предпочитают. Реализовать функцию dp(hat, mask), которая использует мемоизацию для вычисления количества способов распределения шляп. 3⃣Вернуть результат вызова dp(1, 0), который выполняет основное вычисление количества способов распределения шляп. 😎 Решение: class Solution { vector<vector<int>> memo; int done; int n; const int MOD = 1000000007; unordered_map<int, vector<int>> hatsToPeople; public: int numberWays(vector<vector<int>>& hats) { n = hats.size(); for (int i = 0; i < n; i++) { for (int hat: hats[i]) { hatsToPeople[hat].push_back(i); } } done = (1 << n) - 1; memo = vector<vector<int>>(41, vector<int>(done, -1)); return dp(1, 0); } private: int dp(int hat, int mask) { if (mask == done) { return 1; } if (hat > 40) { return 0; } if (memo[hat][mask] != -1) { return memo[hat][mask]; } int ans = dp(hat + 1, mask); if (hatsToPeople.count(hat)) { for (int person: hatsToPeople[hat]) { if ((mask & (1 << person)) == 0) { ans = (ans + dp(hat + 1, mask | (1 << person))) % MOD; } } } memo[hat][mask] = ans; return ans; } }; Ставь 👍 и забирай 📚 Базу знаний
168
14
Задача: 661. Image Smoother Сложность: easy Дан целочисленный матрица img размером m x n, представляющая градации серого изображения. Верните изображение после применения сглаживания к каждой его ячейке. Пример: Input: img = [[1,1,1],[1,0,1],[1,1,1]] Output: [[0,0,0],[0,0,0],[0,0,0]] Explanation: For the points (0,0), (0,2), (2,0), (2,2): floor(3/4) = floor(0.75) = 0 For the points (0,1), (1,0), (1,2), (2,1): floor(5/6) = floor(0.83333333) = 0 For the point (1,1): floor(8/9) = floor(0.88888889) = 0 👨‍💻 Алгоритм: 1⃣Инициализация: Создайте новую матрицу такого же размера, чтобы сохранить результат сглаживания. 2⃣Обработка каждой ячейки: Для каждой ячейки исходной матрицы найдите всех её соседей (включая саму ячейку). Вычислите среднее значение этих ячеек и сохраните его в соответствующей ячейке результирующей матрицы. 3⃣Возврат результата: Верните результирующую матрицу после применения сглаживания ко всем ячейкам. 😎 Решение: class Solution { public: vector<vector<int>> imageSmoother(vector<vector<int>>& img) { int m = img.size(), n = img[0].size(); vector<vector<int>> result(m, vector<int>(n, 0)); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { int count = 0, total = 0; for (int ni = max(0, i - 1); ni <= min(m - 1, i + 1); ni++) { for (int nj = max(0, j - 1); nj <= min(n - 1, j + 1); nj++) { total += img[ni][nj]; count++; } } result[i][j] = total / count; } } return result; } }; Ставь 👍 и забирай 📚 Базу знаний
191
15
Задача: 591. Tag Validator Сложность: hard Дана строка, представляющая фрагмент кода, реализуйте валидатор тегов для разбора кода и определения его корректности. Фрагмент кода считается корректным, если соблюдаются все следующие правила: Код должен быть заключен в корректный закрытый тег. В противном случае код некорректен. Закрытый тег (не обязательно корректный) имеет точно следующий формат: <TAG_NAME>TAG_CONTENT</TAG_NAME>. Среди них <TAG_NAME> — это начальный тег, а </TAG_NAME> — конечный тег. TAG_NAME в начальном и конечном тегах должен быть одинаковым. Закрытый тег корректен, если и только если TAG_NAME и TAG_CONTENT корректны. Корректное TAG_NAME содержит только заглавные буквы и имеет длину в диапазоне [1, 9]. В противном случае TAG_NAME некорректен. Корректное TAG_CONTENT может содержать другие корректные закрытые теги, cdata и любые символы (см. примечание 1), КРОМЕ неподходящих <, неподходящих начальных и конечных тегов, и неподходящих или закрытых тегов с некорректным TAG_NAME. В противном случае TAG_CONTENT некорректен. Начальный тег неподходящий, если нет конечного тега с тем же TAG_NAME, и наоборот. Однако нужно также учитывать проблему несбалансированных тегов, когда они вложены. < неподходящий, если не удается найти последующий >. И когда вы находите < или </, все последующие символы до следующего > должны быть разобраны как TAG_NAME (не обязательно корректный). cdata имеет следующий формат: <![CDATA[CDATA_CONTENT]]>. Диапазон CDATA_CONTENT определяется как символы между <![CDATA[ и первым последующим ]]>. CDATA_CONTENT может содержать любые символы. Функция cdata заключается в том, чтобы запретить валидатору разбирать CDATA_CONTENT, поэтому даже если в нем есть символы, которые могут быть разобраны как тег (корректный или некорректный), вы должны рассматривать их как обычные символы. Пример: Input: code = "<DIV>This is the first line <![CDATA[<div>]]></DIV>" Output: true 👨‍💻 Алгоритм: 1⃣Инициализируйте стек для отслеживания открытых тегов и флаг для определения наличия тегов. Используйте регулярное выражение для проверки корректности TAG_NAME, TAG_CONTENT и CDATA. 2⃣Пройдитесь по строке, проверяя каждый символ. Если встретите <, определите тип тега (начальный, конечный или CDATA). Обновите стек и индексы в зависимости от найденного типа. 3⃣В конце проверьте, что стек пуст (все теги корректно закрыты) и верните результат. 😎 Решение: #include <string> #include <stack> #include <regex> using namespace std; class Solution { stack<string> stack; bool containsTag = false; bool isValidTagName(const string& s, bool ending) { if (ending) { if (!stack.empty() && stack.top() == s) stack.pop(); else return false; } else { containsTag = true; stack.push(s); } return true; } public: bool isValid(string code) { regex pattern("<[A-Z]{0,9}>([^<]*(<((\\/?[A-Z]{1,9}>)|(!\\[CDATA\\[(.*?)]]>)))?)*"); if (!regex_match(code, pattern)) return false; int i = 0; while (i < code.size()) { bool ending = false; if (stack.empty() && containsTag) return false; if (code[i] == '<') { if (code[i + 1] == '!') { i = code.find("]]>", i + 1); if (i == string::npos) return false; continue; } if (code[i + 1] == '/') { i++; ending = true; } int closeIndex = code.find('>', i + 1); if (closeIndex == string::npos || !isValidTagName(code.substr(i + 1, closeIndex - (i + 1)), ending)) return false; i = closeIndex; } i++; } return stack.empty(); } }; Ставь 👍 и забирай 📚 Базу знаний
177
16
Задача: 1469. Find All The Lonely Nodes Сложность: easy В бинарном дереве одиночный узел — это узел, который является единственным ребёнком своего родительского узла. Корень дерева не является одиночным, так как у него нет родительского узла. Дано корневое значение бинарного дерева. Верните массив, содержащий значения всех одиночных узлов в дереве. Верните список в любом порядке. Пример: Input: root = [7,1,4,6,null,5,3,null,null,null,null,null,2] Output: [6,2] Explanation: Light blue nodes are lonely nodes. Please remember that order doesn't matter, [2,6] is also an acceptable answer. 👨‍💻 Алгоритм: 1⃣Определите рекурсивную функцию DFS, которая принимает корень дерева, булеву переменную isLonely и список одиночных узлов ans в качестве аргументов. Если корень равен NULL, завершите выполнение функции. 2⃣Если isLonely равен true, добавьте значение корня в список ans. Рекурсивно обрабатывайте левого потомка корня, устанавливая флаг isLonely в true, если правый потомок равен NULL, и правого потомка, устанавливая флаг isLonely в true, если левый потомок равен NULL. 3⃣Вызовите DFS с корнем и false в качестве значения isLonely. Верните ans. 😎 Решение: #include <vector> using namespace std; struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; class Solution { public: void DFS(TreeNode* root, bool isLonely, vector<int>& ans) { if (root == NULL) { return; } if (isLonely) { ans.push_back(root->val); } DFS(root->left, root->right == NULL, ans); DFS(root->right, root->left == NULL, ans); } vector<int> getLonelyNodes(TreeNode* root) { vector<int> ans; DFS(root, false, ans); return ans; } }; Ставь 👍 и забирай 📚 Базу знаний
232
17
Задача: 283. Move Zeroes Сложность: easy Дан целочисленный массив nums. Переместите все нули в конец массива, сохраняя относительный порядок ненулевых элементов. Обратите внимание, что вы должны сделать это на месте, не создавая копию массива. Пример: Input: nums = [0,1,0,3,12] Output: [1,3,12,0,0] 👨‍💻 Алгоритм: 1⃣Инициализация указателей: Инициализируйте два указателя: lastNonZeroFoundAt для отслеживания позиции последнего ненулевого элемента и cur для итерации по массиву. 2⃣Итерация и обмен элементами: Итерируйтесь по массиву с помощью указателя cur. Если текущий элемент ненулевой, поменяйте его местами с элементом, на который указывает lastNonZeroFoundAt, и продвиньте указатель lastNonZeroFoundAt. 3⃣Завершение итерации: Повторяйте шаг 2 до конца массива. В итоге все нули будут перемещены в конец массива, сохраняя относительный порядок ненулевых элементов. 😎 Решение: void moveZeroes(vector<int>& nums) { for (int lastNonZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) { if (nums[cur] != 0) { swap(nums[lastNonZeroFoundAt++], nums[cur]); } } } Ставь 👍 и забирай 📚 Базу знаний
263
18
Задача: 870. Advantage Shuffle Сложность: medium Даны два целочисленных массива nums1 и nums2 одинаковой длины. Преимущество nums1 относительно nums2 — это количество индексов i, для которых nums1[i] > nums2[i]. Верните любую перестановку nums1, которая максимизирует его преимущество относительно nums2. Пример: Input: nums1 = [2,7,11,15], nums2 = [1,10,4,11] Output: [2,11,7,15] 👨‍💻 Алгоритм: 1⃣Отсортируйте nums1 и nums2. Для каждой карты a из отсортированного nums1 определите, может ли она побить текущую наименьшую карту b из отсортированного nums2. Если да, добавьте a в assigned[b], если нет, добавьте a в remaining. 2⃣После распределения всех карт из nums1, используйте assigned и remaining для построения итогового результата. Для каждой карты b из nums2, если assigned[b] не пуст, добавьте в результат последнюю карту из assigned[b], иначе добавьте последнюю карту из remaining. 3⃣Верните итоговый результат. 😎 Решение: class Solution { public: vector<int> advantageCount(vector<int>& A, vector<int>& B) { vector<int> sortedA(A); sort(sortedA.begin(), sortedA.end()); vector<pair<int, int>> sortedB; for (int i = 0; i < B.size(); ++i) sortedB.push_back({B[i], i}); sort(sortedB.begin(), sortedB.end()); unordered_map<int, deque<int>> assigned; for (int b: B) assigned[b] = {}; deque<int> remaining; int j = 0; for (int a: sortedA) { if (a > sortedB[j].first) { assigned[sortedB[j++].first].push_back(a); } else { remaining.push_back(a); } } vector<int> ans(B.size()); for (int i = 0; i < B.size(); ++i) { if (assigned[B[i]].size() > 0) { ans[i] = assigned[B[i]].front(); assigned[B[i]].pop_front(); } else { ans[i] = remaining.front(); remaining.pop_front(); } } return ans; } }; Ставь 👍 и забирай 📚 Базу знаний
280
19
Задача: 775. Global and Local Inversions Сложность: medium Дан массив целых чисел nums длиной n, который представляет собой перестановку всех чисел в диапазоне [0, n - 1]. Число глобальных инверсий — это количество различных пар (i, j), где: 0 <= i < j < n nums[i] > nums[j] Число локальных инверсий — это количество индексов i, где: 0 <= i < n - 1 nums[i] > nums[i + 1] Верните true, если количество глобальных инверсий равно количеству локальных инверсий. Пример: Input: nums = [1,0,2] Output: true Explanation: There is 1 global inversion and 1 local inversion. 👨‍💻 Алгоритм: 1⃣Локальная инверсия также является глобальной инверсией. Таким образом, нам нужно проверить, есть ли в нашей перестановке какие-либо нелокальные инверсии (A[i] > A[j], i < j) с j - i > 1. 2⃣Для этого мы можем перебрать каждый индекс i и проверить, есть ли индекс j, такой что j > i + 1 и nums[i] > nums[j]. Если такой индекс найден, это будет означать наличие нелокальной инверсии. 3⃣Если для всех индексов i условие выше не выполняется, это значит, что количество глобальных инверсий равно количеству локальных инверсий, и мы возвращаем true. В противном случае, если хотя бы одна нелокальная инверсия найдена, мы возвращаем false. 😎 Решение: class Solution { public: bool isIdealPermutation(vector<int>& A) { int N = A.size(); for (int i = 0; i < N; ++i) for (int j = i + 2; j < N; ++j) if (A[i] > A[j]) return false; return true; } }; Ставь 👍 и забирай 📚 Базу знаний
265
20
Задача: 733. Flood Fill Сложность: easy Изображение представлено в виде целочисленной сетки m x n, где image[i][j] - значение пикселя изображения. Вам также даны три целых числа sr, sc и color. Вы должны выполнить заливку изображения, начиная с пикселя image[sr][sc]. Чтобы выполнить заливку, рассмотрите начальный пиксель, плюс все пиксели, соединенные по 4-м направлениям с начальным пикселем, того же цвета, что и начальный пиксель, плюс все пиксели, соединенные по 4-м направлениям с этими пикселями (также того же цвета), и так далее. Замените цвет всех вышеупомянутых пикселей на цвет. Верните измененное изображение после выполнения заливки. Пример: Input: image = [[1,1,1],[1,1,0],[1,0,1]], sr = 1, sc = 1, color = 2 Output: [[2,2,2],[2,2,0],[2,0,1]] 👨‍💻 Алгоритм: 1⃣Получите цвет начального пикселя. 2⃣Используйте обход в глубину (DFS) или обход в ширину (BFS) для замены цвета всех пикселей, которые соединены с начальным пикселем и имеют тот же цвет. 3⃣Обновите изображение и верните его. 😎 Решение: class Solution { public: vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) { int originalColor = image[sr][sc]; if (originalColor == color) { return image; } dfs(image, sr, sc, originalColor, color); return image; } private: void dfs(vector<vector<int>>& image, int x, int y, int originalColor, int newColor) { if (x < 0 || x >= image.size() || y < 0 || y >= image[0].size() || image[x][y] != originalColor) { return; } image[x][y] = newColor; dfs(image, x + 1, y, originalColor, newColor); dfs(image, x - 1, y, originalColor, newColor); dfs(image, x, y + 1, originalColor, newColor); dfs(image, x, y - 1, originalColor, newColor); } }; Ставь 👍 и забирай 📚 Базу знаний
276