uz
Feedback
C/C++ | LeetCode

C/C++ | LeetCode

Kanalga Telegram’da o‘tish

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

Ko'proq ko'rsatish
3 231
Obunachilar
+224 soatlar
+37 kun
-330 kun
Obunachilarni jalb qilish
Okt '26
Oktabr '26
+7
0 kanalda
Sentabr '26
+42
0 kanalda
Get PRO
Avgust '26
+32
0 kanalda
Get PRO
Iyul '26
+42
0 kanalda
Get PRO
Iyun '26
+30
1 kanalda
Get PRO
May '26
+35
0 kanalda
Get PRO
Aprel '26
+35
0 kanalda
Get PRO
Mart '26
+32
0 kanalda
Get PRO
Fevral '26
+45
0 kanalda
Get PRO
Yanvar '26
+35
0 kanalda
Get PRO
Dekabr '25
+37
0 kanalda
Get PRO
Noyabr '25
+84
0 kanalda
Get PRO
Oktabr '25
+43
0 kanalda
Get PRO
Sentabr '25
+35
0 kanalda
Get PRO
Avgust '25
+40
0 kanalda
Get PRO
Iyul '25
+40
1 kanalda
Get PRO
Iyun '25
+43
0 kanalda
Get PRO
May '25
+44
0 kanalda
Get PRO
Aprel '25
+61
0 kanalda
Get PRO
Mart '25
+60
1 kanalda
Get PRO
Fevral '25
+179
3 kanalda
Get PRO
Yanvar '25
+79
53 kanalda
Get PRO
Dekabr '24
+64
0 kanalda
Get PRO
Noyabr '24
+91
1 kanalda
Get PRO
Oktabr '24
+424
13 kanalda
Get PRO
Sentabr '24
+1 488
331 kanalda
Get PRO
Avgust '24
+91
0 kanalda
Get PRO
Iyul '24
+826
219 kanalda
Get PRO
Iyun '24
+1 211
232 kanalda
Sana
Obunachilarni jalb qilish
Esdaliklar
Kanallar
05 Oktabr+3
04 Oktabr+2
03 Oktabr0
02 Oktabr+1
01 Oktabr+1
Kanal postlari
Задача: 40. Combination Sum II Сложность: medium Дан массив candidates и число target. Найдите все уникальные комбинации, где сумма элементов равна target. Каждое число можно использовать только один раз. Пример:
Input: candidates = [10,1,2,7,6,1,5], target = 8 Output: [[1,1,6],[1,2,5],[1,7],[2,6]]
👨‍💻 Алгоритм: 1⃣Отсортировать и подсчитать количество каждого уникального элемента, чтобы избежать дубликатов. 2⃣Запустить рекурсивный backtrack, на каждом шаге выбирая доступный элемент, уменьшая его частоту и остаток target. 3⃣Если remain == 0 — сохранить комбинацию; иначе — откатить шаг (уменьшение глубины, восстановление частоты и удаление элемента из комбинации). 😎 Решение:
class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<vector<int>> results;
        vector<int> comb;
        map<int, int> counter;
        for (int candidate : candidates) {
            counter[candidate]++;
        }
        vector<pair<int, int>> counterList(counter.begin(), counter.end());
        backtrack(comb, target, 0, counterList, results);
        return results;
    }

private:
    void backtrack(vector<int>& comb, int remain, int curr,
                   vector<pair<int, int>>& counter,
                   vector<vector<int>>& results) {
        if (remain == 0) {
            results.push_back(comb);
            return;
        } else if (remain < 0) {
            return;
        }

        for (int nextCurr = curr; nextCurr < counter.size(); ++nextCurr) {
            auto& [candidate, freq] = counter[nextCurr];
            if (freq == 0) continue;

            comb.push_back(candidate);
            --freq;

            backtrack(comb, remain - candidate, nextCurr, counter, results);

            ++freq;
            comb.pop_back();
        }
    }
};
Ставь 👍 и забирай 📚 Базу знаний

2
Задача: 1014. Best Sightseeing Pair Сложность: easy Вам дан целочисленный массив values, в котором values[i] представляет собой значение i-й достопримечательности. Две достопримечательности i и j имеют расстояние j - i между собой. Оценка пары (i < j) достопримечательностей равна values[i] + values[j] + i - j: сумма значений достопримечательностей минус расстояние между ними. Возвращается максимальная оценка пары достопримечательностей. Пример: Input: values = [8,1,5,2,6] Output: 11 👨‍💻 Алгоритм: 1⃣Инициализация переменных: Инициализируйте переменную max_score для хранения максимальной оценки пары. Инициализируйте переменную max_i_plus_value для хранения максимального значения выражения values[i] + i при проходе по массиву. 2⃣Проход по массиву: Пройдитесь по массиву начиная с первого элемента и для каждого элемента values[j] вычислите текущую оценку пары как values[j] - j + max_i_plus_value. Обновите значение max_score, если текущая оценка больше. Обновите значение max_i_plus_value, если текущий элемент values[j] + j больше предыдущего max_i_plus_value. 3⃣Возврат результата: Верните значение max_score как максимальную оценку пары достопримечательностей. 😎 Решение: class Solution { public: int maxScoreSightseeingPair(vector<int>& values) { int max_score = 0; int max_i_plus_value = values[0]; for (int j = 1; j < values.size(); ++j) { max_score = max(max_score, max_i_plus_value + values[j] - j); max_i_plus_value = max(max_i_plus_value, values[j] + j); } return max_score; } }; Ставь 👍 и забирай 📚 Базу знаний
138
3
Задача: 1034. Coloring A Border Сложность: medium Вам дана целочисленная матричная сетка m x n и три целых числа row, col и color. Каждое значение в сетке представляет собой цвет квадрата сетки в данном месте. Два квадрата называются смежными, если они находятся рядом друг с другом в любом из 4 направлений. Два квадрата принадлежат одному связанному компоненту, если они имеют одинаковый цвет и являются смежными. Граница связанного компонента - это все квадраты в связанном компоненте, которые либо смежны (по крайней мере) с квадратом, не входящим в компонент, либо находятся на границе сетки (в первой или последней строке или столбце). Вы должны окрасить границу связанного компонента, содержащего квадрат grid[row][col], в цвет. Верните конечную сетку. Пример: Input: grid = [[1,1],[1,2]], row = 0, col = 0, color = 3 Output: [[3,3],[3,2]] 👨‍💻 Алгоритм: 1⃣Поиск связанного компонента: Используйте поиск в глубину (DFS) или поиск в ширину (BFS), чтобы найти все клетки, принадлежащие связанному компоненту, содержащему клетку grid[row][col]. Запомните все клетки, которые принадлежат этому компоненту. 2⃣Определение границ компонента: Для каждой клетки в связанном компоненте проверьте, является ли она границей. Клетка является границей, если она находится на краю сетки или если хотя бы одна из её соседних клеток не принадлежит связанному компоненту или имеет другой цвет. 3⃣Окрашивание границы: Измените цвет всех клеток, являющихся границами, на заданный цвет. 😎 Решение: class Solution { public: vector<vector<int>> colorBorder(vector<vector<int>>& grid, int row, int col, int color) { int m = grid.size(), n = grid[0].size(); int original_color = grid[row][col]; vector<vector<bool>> visited(m, vector<bool>(n, false)); vector<pair<int, int>> borders; function<void(int, int)> dfs = [&](int r, int c) { visited[r][c] = true; bool is_border = false; for (auto [dr, dc] : vector<pair<int, int>>{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}) { int nr = r + dr, nc = c + dc; if (nr >= 0 && nr < m && nc >= 0 && nc < n) { if (!visited[nr][nc]) { if (grid[nr][nc] == original_color) { dfs(nr, nc); } else { is_border = true; } } } else { is_border = true; } } if (is_border || r == 0 || r == m - 1 || c == 0 || c == n - 1) { borders.emplace_back(r, c); } }; dfs(row, col); for (auto [r, c] : borders) { grid[r][c] = color; } return grid; } }; Ставь 👍 и забирай 📚 Базу знаний
148
4
Задача: 527. Word Abbreviation Сложность: hard Дано массив уникальных строк words, верните минимально возможные сокращения для каждого слова. Правила сокращения строки следующие: Первоначальное сокращение для каждого слова: первый символ, затем количество символов между первым и последним символом, затем последний символ. Если более одного слова имеют одинаковое сокращение, выполните следующее: Увеличьте префикс (символы в первой части) каждого из их сокращений на 1. Например, начнем с слов ["abcdef", "abndef"], оба изначально сокращены как "a4f". Последовательность операций будет следующей: ["a4f", "a4f"] -> ["ab3f", "ab3f"] -> ["abc2f", "abn2f"]. Эта операция повторяется до тех пор, пока каждое сокращение не станет уникальным. В конце, если сокращение не сделало слово короче, оставьте его в исходном виде. Пример: Input: words = ["like","god","internal","me","internet","interval","intension","face","intrusion"] Output: ["l2e","god","internal","me","i6t","interval","inte4n","f2e","intr4n"] 👨‍💻 Алгоритм: 1⃣ Инициализация и создание начальных сокращений: Создайте массив для хранения сокращений и массив для отслеживания длины префикса каждого слова. Для каждого слова создайте начальное сокращение с использованием первого символа, количества символов между первым и последним символом и последнего символа. 2⃣ Обработка коллизий: Для каждого слова проверьте, не совпадает ли его сокращение с уже существующими сокращениями. Если сокращение не уникально, увеличьте длину префикса и повторите проверку. 3⃣ Возврат результата: Верните окончательные сокращения для каждого слова, убедившись, что они минимально возможны и уникальны. 😎 Решение: class Solution { public: vector<string> wordsAbbreviation(vector<string>& words) { int n = words.size(); vector<string> ans(n); vector<int> prefix(n, 0); for (int i = 0; i < n; ++i) ans[i] = abbrev(words[i], 0); for (int i = 0; i < n; ++i) { while (true) { unordered_set<int> dupes; for (int j = i + 1; j < n; ++j) { if (ans[i] == ans[j]) dupes.insert(j); } if (dupes.empty()) break; dupes.insert(i); for (int k : dupes) { ans[k] = abbrev(words[k], ++prefix[k]); } } } return ans; } private: string abbrev(const string& word, int i) { int n = word.size(); if (n - i <= 3) return word; return word.substr(0, i + 1) + to_string(n - i - 2) + word.back(); } }; Ставь 👍 и забирай 📚 Базу знаний
140
5
Задача: 952. Largest Component Size by Common Factor Сложность: hard Для бинарного дерева T мы можем определить операцию переворота следующим образом: выбираем любой узел и меняем местами левое и правое дочерние поддеревья. Бинарное дерево X эквивалентно бинарному дереву Y тогда и только тогда, когда мы можем сделать X равным Y после некоторого количества операций переворота. Учитывая корни двух бинарных деревьев root1 и root2, верните true, если эти два дерева эквивалентны перевороту, или false в противном случае. Пример: Input: nums = [4,6,15,35] Output: 4 👨‍💻 Алгоритм: 1⃣Построить граф, в котором узлы представляют числа из массива, а ребра между узлами существуют, если два числа имеют общий делитель больше 1. 2⃣Использовать алгоритм Union-Find для объединения узлов в связные компоненты. Для каждого числа в массиве nums найти его простые делители и использовать их для объединения узлов. 3⃣Найти размер наибольшей связной компоненты. 😎 Решение: class Solution { public: int largestComponentSize(vector<int>& nums) { unordered_map<int, int> parent; unordered_map<int, int> rank; for (int num : nums) { parent[num] = num; rank[num] = 0; } function<int(int)> find = [&](int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; }; auto unionFind = [&](int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { if (rank[rootX] > rank[rootY]) { parent[rootY] = rootX; } else if (rank[rootX] < rank[rootY]) { parent[rootX] = rootY; } else { parent[rootY] = rootX; rank[rootX]++; } } }; auto primeFactors = [&](int n) { unordered_set<int> factors; int d = 2; while (d * d <= n) { while (n % d == 0) { factors.insert(d); n /= d; } d++; } if (n > 1) { factors.insert(n); } return factors; }; unordered_map<int, vector<int>> primeToIndex; for (int num : nums) { auto primes = primeFactors(num); for (int prime : primes) { primeToIndex[prime].push_back(num); } } for (const auto& primes : primeToIndex) { for (int i = 1; i < primes.second.size(); i++) { unionFind(primes.second[0], primes.second[i]); } } unordered_map<int, int> size; for (int num : nums) { int root = find(num); size[root]++; } int maxSize = 0; for (const auto& [key, value] : size) { maxSize = max(maxSize, value); } return maxSize; } }; Ставь 👍 и забирай 📚 Базу знаний
132
6
Задача: 474. Ones and Zeroes Сложность: medium Дан массив двоичных строк strs и два целых числа m и n. Верните размер наибольшего подмножества strs, такого что в подмножестве содержится не более m нулей и n единиц. Множество x является подмножеством множества y, если все элементы множества x также являются элементами множества y. Пример: Input: strs = ["10","0001","111001","1","0"], m = 5, n = 3 Output: 4 Explanation: The largest subset with at most 5 0's and 3 1's is {"10", "0001", "1", "0"}, so the answer is 4. Other valid but smaller subsets include {"0001", "1"} and {"10", "1", "0"}. {"111001"} is an invalid subset because it contains 4 1's, greater than the maximum of 3. 👨‍💻 Алгоритм: 1⃣Рассматриваем все возможные подмножества, прерывая цикл, если количество нулей превышает m или количество единиц превышает n. 2⃣Считаем количество нулей и единиц в каждом подмножестве. 3⃣Выбираем наибольшее подмножество, соответствующее условиям, и возвращаем его размер. 😎 Решение: #include <vector> #include <string> #include <algorithm> class Solution { public: int findMaxForm(std::vector<std::string>& strs, int m, int n) { int maxlen = 0; for (int i = 0; i < (1 << strs.size()); ++i) { int zeroes = 0, ones = 0, len = 0; for (int j = 0; j < 32; ++j) { if ((i & (1 << j)) != 0) { auto count = countZeroesOnes(strs[j]); zeroes += count[0]; ones += count[1]; if (zeroes > m || ones > n) break; ++len; } } if (zeroes <= m && ones <= n) maxlen = std::max(maxlen, len); } return maxlen; } std::vector<int> countZeroesOnes(const std::string& s) { std::vector<int> c(2, 0); for (char ch : s) { ++c[ch - '0']; } return c; } }; Ставь 👍 и забирай 📚 Базу знаний
148
7
Задача: 998. Maximum Binary Tree II Сложность: medium Максимальное дерево - это дерево, в котором каждый узел имеет значение большее, чем любое другое значение в его поддереве. Вам дан корень максимального двоичного дерева и целое число val. Как и в предыдущей задаче, данное дерево было построено из списка a (root = Construct(a)) рекурсивно с помощью следующей процедуры Construct(a): Если a пусто, верните null. В противном случае пусть a[i] - наибольший элемент a. Создайте корневой узел со значением a[i]. Левым ребенком root будет Construct([a[0], a[1], ..., a[i - 1]]). Правым ребенком root будет Construct([a[i + 1], a[i + 2], ..., a[a.length])...., a[a.length - 1]]). Возвращаем root. Обратите внимание, что нам не было дано непосредственно a, а только корневой узел root = Construct(a). Предположим, что b - это копия a с добавленным к ней значением val. Гарантируется, что b имеет уникальные значения. Возвращаем Construct(b). Пример: Input: n = 2, trust = [[1,2]] Output: 2 👨‍💻 Алгоритм: 1⃣Поиск места вставки: Итерируйте через дерево, начиная с корня. Найдите место для вставки нового значения val так, чтобы дерево оставалось максимальным деревом. Если значение val больше, чем значение текущего узла, создайте новый узел с val и сделайте текущий узел его левым ребенком. 2⃣Вставка нового узла: Если значение val меньше, чем значение текущего узла, продолжайте спускаться по правому поддереву, пока не найдете место для вставки. 3⃣Создание нового дерева: После вставки нового узла убедитесь, что дерево сохраняет свои свойства максимального дерева. 😎 Решение: struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; class Solution { public: TreeNode* insertIntoMaxTree(TreeNode* root, int val) { if (!root || val > root->val) { TreeNode* newNode = new TreeNode(val); newNode->left = root; return newNode; } root->right = insertIntoMaxTree(root->right, val); return root; } }; Ставь 👍 и забирай 📚 Базу знаний
182
8
Задача: 32. Longest Valid Parentheses Сложность: hard Учитывая строку, содержащую только символы «(» и «)», верните длину самой длинной допустимой (правильно сформированной) подстроки скобок. Пример: Input: s = "(()" Output: 2 👨‍💻 Алгоритм: 1⃣Используем стек для хранения индексов, начальное значение — -1. 2⃣Проходим по строке: если '(', кладем индекс в стек, если ')' — извлекаем элемент. 3⃣Если после извлечения стек пуст — кладем текущий индекс, иначе — обновляем максимум длины как i - stack.top(). 😎 Решение: class Solution { public: int longestValidParentheses(string s) { stack<int> stack; int m = 0; stack.push(-1); for (int i = 0; i < s.length(); i++) { if (s[i] == '(') { stack.push(i); } else { stack.pop(); if (stack.empty()) { stack.push(i); } else { m = max(m, (i - stack.top())); } } } return m; } }; Ставь 👍 и забирай 📚 Базу знаний
195
9
Задача: 1365. How Many Numbers Are Smaller Than the Current Number Сложность: easy Дан массив nums. Для каждого элемента nums[i] определите, сколько чисел в массиве меньше его. То есть, для каждого nums[i] вам нужно посчитать количество допустимых j, таких что j != i и nums[j] < nums[i]. Верните ответ в виде массива. Пример: Input: nums = [6,5,4,8] Output: [2,1,0,3] 👨‍💻 Алгоритм: 1⃣Создание копии и сортировка массива: Создайте отсортированную копию массива nums, чтобы легко находить количество элементов, меньших текущего. 2⃣Поиск индекса каждого элемента: Для каждого элемента nums[i] найдите его индекс в отсортированной копии массива. Этот индекс указывает количество элементов, меньших nums[i]. 3⃣Формирование ответа: Сформируйте массив ответов, где каждый элемент будет соответствовать количеству чисел, меньших текущего. 😎 Решение: #include <vector> #include <algorithm> class Solution { public: std::vector<int> smallerNumbersThanCurrent(std::vector<int>& nums) { std::vector<int> sortedNums = nums; std::sort(sortedNums.begin(), sortedNums.end()); std::vector<int> result; for (int num : nums) { result.push_back(std::find(sortedNums.begin(), sortedNums.end(), num) - sortedNums.begin()); } return result; } }; Ставь 👍 и забирай 📚 Базу знаний
253
10
Задача: 1024. Video Stitching Сложность: 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 👨‍💻 Алгоритм: 1⃣Сортировка клипов: Отсортируйте клипы по начальным значениям. Если начальные значения равны, отсортируйте по конечным значениям в убывающем порядке. 2⃣Выбор клипов: Используйте жадный алгоритм для выбора клипов. Начните с начальной точки 0 и двигайтесь вперед, выбирая клип, который может покрыть наибольший диапазон. Если обнаруживается, что начальная точка текущего клипа больше текущей позиции, это означает, что клипы не могут покрыть промежуток, и нужно вернуть -1. 3⃣Проверка покрытия: Продолжайте процесс, пока не покроете весь диапазон от 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; } }; Ставь 👍 и забирай 📚 Базу знаний
257
11
Задача: 869. Reordered Power of 2 Сложность: medium Дано целое число n. Мы можем переставить цифры числа в любом порядке (включая исходный порядок), при этом ведущая цифра не должна быть нулем. Верните true, если и только если мы можем сделать это так, чтобы полученное число было степенью двойки. Пример: Input: n = 1 Output: true 👨‍💻 Алгоритм: 1⃣Сгенерируйте все перестановки цифр числа, размещая любую цифру на первой позиции (start = 0), затем любую из оставшихся цифр на второй позиции (start = 1) и так далее. В Python можно использовать встроенную функцию itertools.permutations. 2⃣Проверьте, что перестановка представляет собой степень двойки, убедившись, что в перестановке нет ведущего нуля, и удаляя все множители 2. Если результат равен 1 (то есть, он не содержал других множителей, кроме 2), то это была степень двойки. В Python можно использовать проверку bin(N).count('1') == 1. 3⃣Верните true, если хотя бы одна перестановка является степенью двойки, иначе верните false. 😎 Решение: class Solution { public: bool reorderedPowerOf2(int N) { string A = to_string(N); sort(A.begin(), A.end()); for (int i = 0; i < 30; ++i) { string B = to_string(1 << i); sort(B.begin(), B.end()); if (A == B) return true; } return false; } }; Ставь 👍 и забирай 📚 Базу знаний
237
12
Задача: 1033. Moving Stones Until Consecutive Сложность: medium На оси X расположены три камня в разных позициях. Вам даны три целых числа a, b и c - позиции камней. За одно движение вы берете камень в конечной точке (т. е. либо в самой низкой, либо в самой высокой позиции камня) и перемещаете его в незанятую позицию между этими конечными точками. Формально, допустим, камни в данный момент находятся в позициях x, y и z, причем x < y < z. Вы берете камень в позиции x или z и перемещаете его в целочисленную позицию k, причем x < k < z и k != y. Игра заканчивается, когда вы больше не можете сделать ни одного хода (то есть камни находятся в трех последовательных позициях). Возвращается целочисленный массив answer длины 2, где: answer[0] - минимальное количество ходов, которое вы можете сыграть, а answer[1] - максимальное количество ходов, которое вы можете сыграть. Пример: Input: a = 3, b = 5, c = 1 Output: [1,2] 👨‍💻 Алгоритм: 1⃣Сортировка позиций: Убедитесь, что позиции камней отсортированы в порядке возрастания. Обозначим отсортированные позиции как x, y и z. 2⃣Вычисление минимальных ходов: Если камни уже находятся в последовательных позициях (то есть y - x == 1 и z - y == 1), минимальное количество ходов равно 0. Если два камня находятся в соседних позициях, а третий камень на расстоянии более чем одна позиция, минимальное количество ходов равно 1. В остальных случаях минимальное количество ходов равно 2. 3⃣Вычисление максимальных ходов: Максимальное количество ходов равно сумме расстояний между соседними камнями минус 2, то есть (y - x - 1) + (z - y - 1). 😎 Решение: vector<int> numMovesStones(int a, int b, int c) { vector<int> stones = {a, b, c}; sort(stones.begin(), stones.end()); int x = stones[0], y = stones[1], z = stones[2]; int min_moves = (y - x <= 2 || z - y <= 2) ? ((y - x == 1 && z - y == 1) ? 0 : 1) : 2; int max_moves = (y - x - 1) + (z - y - 1); return {min_moves, max_moves}; } Ставь 👍 и забирай 📚 Базу знаний
226
13
Задача: 1168. Optimize Water Distribution in a Village Сложность: hard В деревне есть n домов. Мы хотим обеспечить все дома водой, строя колодцы и прокладывая трубы. Для каждого дома i мы можем либо построить колодец внутри него непосредственно с затратами wells[i - 1] (обратите внимание на -1 из-за нумерации с нуля), либо провести воду из другого колодца с помощью трубы. Затраты на прокладку труб между домами даны в массиве pipes, где каждый pipes[j] = [house1j, house2j, costj] представляет собой стоимость соединения дома house1j и дома house2j с помощью трубы. Соединения двунаправленные, и между одними и теми же домами могут быть несколько допустимых соединений с разными затратами. Верните минимальные оhttps://leetcode.com/problems/optimize-water-distribution-in-a-village/Figures/1168/PrimAlgDemo.gifбщие затраты на обеспечение всех домов водой. Пример: Input: n = 3, wells = [1,2,2], pipes = [[1,2,1],[2,3,1]] Output: 3 Explanation: The image shows the costs of connecting houses using pipes. The best strategy is to build a well in the first house with cost 1 and connect the other houses to it with cost 2 so the total cost is 3. 👨‍💻 Алгоритм: 1⃣Представление графа: Постройте список смежности для представления графа, где вершины и ребра соответствуют домам и трубам. Список смежности можно представить в виде списка списков или словаря списков. 2⃣Набор для вершин: Используйте набор для поддержания всех вершин, добавленных в окончательное минимальное остовное дерево (MST) во время его построения. С помощью набора можно определить, была ли вершина уже добавлена или нет. 3⃣Очередь с приоритетом (куча): Используйте кучу для реализации жадной стратегии. На каждом шаге определяйте лучшее ребро для добавления на основе стоимости его добавления в дерево. Куча позволяет извлекать минимальный элемент за константное время и удалять минимальный элемент за логарифмическое время. Это идеально подходит для нашей задачи повторного нахождения ребра с наименьшей стоимостью. 😎 Решение: class Solution { public: int minCostToSupplyWater(int n, vector<int>& wells, vector<vector<int>>& pipes) { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> edgesHeap; vector<vector<pair<int, int>>> graph(n + 1); for (int i = 0; i < wells.size(); ++i) { graph[0].emplace_back(wells[i], i + 1); edgesHeap.emplace(wells[i], i + 1); } for (const auto& pipe : pipes) { int house1 = pipe[0], house2 = pipe[1], cost = pipe[2]; graph[house1].emplace_back(cost, house2); graph[house2].emplace_back(cost, house1); } unordered_set<int> mstSet{0}; int totalCost = 0; while (mstSet.size() < n + 1) { auto [cost, nextHouse] = edgesHeap.top(); edgesHeap.pop(); if (mstSet.count(nextHouse)) continue; mstSet.insert(nextHouse); totalCost += cost; for (const auto& [nextCost, neighbor] : graph[nextHouse]) { if (!mstSet.count(neighbor)) { edgesHeap.emplace(nextCost, neighbor); } } } return totalCost; } }; Ставь 👍 и забирай 📚 Базу знаний
247
14
Задача: 680. Valid Palindrome II Сложность: easy Дана строка s, вернуть true, если s может быть палиндромом после удаления не более одного символа из нее. Пример: Input: s = "aba" Output: true 👨‍💻 Алгоритм: 1⃣Создайте вспомогательную функцию checkPalindrome, которая принимает строку s и два указателя i и j. Эта функция возвращает логическое значение, указывающее, является ли подстрока s.substring(i, j) палиндромом. 2⃣Инициализируйте два указателя: i = 0 и j = s.length() - 1. Пока i < j, проверьте, совпадают ли символы в индексах i и j. Если нет, это значит, что нам нужно удалить один из этих символов. 3⃣Попробуйте оба варианта, используя checkPalindrome. Верните true, если либо checkPalindrome(s, i, j - 1), либо checkPalindrome(s, i + 1, j) возвращает true. Если мы выходим из цикла while, это значит, что исходная строка является палиндромом. Поскольку нам не нужно было использовать удаление, следует вернуть true 😎 Решение: class Solution { bool checkPalindrome(const string& s, int i, int j) { while (i < j) { if (s[i] != s[j]) { return false; } i++; j--; } return true; } public: bool validPalindrome(string s) { int i = 0; int j = s.size() - 1; while (i < j) { if (s[i] != s[j]) { return checkPalindrome(s, i, j - 1) || checkPalindrome(s, i + 1, j); } i++; j--; } return true; } }; Ставь 👍 и забирай 📚 Базу знаний
317
15
Задача: 974. Subarray Sums Divisible by 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] 👨‍💻 Алгоритм: 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. 😎 Решение: 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; } }; Ставь 👍 и забирай 📚 Базу знаний
289
16
Задача: 1801. Number of Orders in the Backlog Сложность: medium Дан двумерный целочисленный массив orders, где каждый элемент orders[i] = [pricei, amounti, orderTypei] обозначает, что было размещено amounti заказов типа orderTypei по цене pricei. Тип заказа orderTypei может быть: - 0, если это партия заказов на покупку, или - 1, если это партия заказов на продажу. Обратите внимание, что orders[i] представляет собой партию из amounti независимых заказов с одинаковой ценой и типом. Все заказы, представленные orders[i], будут размещены перед всеми заказами, представленными orders[i+1] для всех допустимых i. Существует список невыполненных заказов (backlog), который изначально пуст. При размещении заказа происходит следующее: - Если это заказ на покупку, вы просматриваете заказ на продажу с наименьшей ценой в списке невыполненных заказов. Если цена этого заказа на продажу меньше или равна цене текущего заказа на покупку, они будут сопоставлены и выполнены, и этот заказ на продажу будет удален из списка. В противном случае заказ на покупку добавляется в список невыполненных заказов. - Если это заказ на продажу, вы просматриваете заказ на покупку с наибольшей ценой в списке невыполненных заказов. Если цена этого заказа на покупку больше или равна цене текущего заказа на продажу, они будут сопоставлены и выполнены, и этот заказ на покупку будет удален из списка. В противном случае заказ на продажу добавляется в список невыполненных заказов. Верните общее количество заказов в списке невыполненных заказов после размещения всех заказов из входных данных. Поскольку это число может быть большим, верните его по модулю 10^9 + 7. Пример: Input: orders = [[10,5,0],[15,2,1],[25,1,1],[30,4,0]] Output: 6 👨‍💻 Алгоритм: 1⃣Обрабатывайте каждый заказ в orders. Для заказа на покупку сравните с самыми дешевыми заказами на продажу в списке и выполняйте их при возможности, иначе добавьте в список. 2⃣Для заказа на продажу сравните с самыми дорогими заказами на покупку в списке и выполняйте их при возможности, иначе добавьте в список. 3⃣Подсчитайте общее количество оставшихся заказов в списке и верните его по модулю 10^9 + 7. 😎 Решение: class Solution { public: int getNumberOfBacklogOrders(vector<vector<int>>& orders) { const int MOD = 1'000'000'007; priority_queue<pair<int, int>> buyOrders; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> sellOrders; for (const auto& order : orders) { int price = order[0], amount = order[1], orderType = order[2]; auto& primaryQueue = orderType == 0 ? sellOrders : buyOrders; auto& secondaryQueue = orderType == 0 ? buyOrders : sellOrders; while (amount > 0 && !primaryQueue.empty() && (orderType == 0 ? primaryQueue.top().first <= price : primaryQueue.top().first >= price)) { auto [topPrice, topAmount] = primaryQueue.top(); primaryQueue.pop(); int executedAmount = min(amount, topAmount); amount -= executedAmount; if (topAmount > executedAmount) primaryQueue.emplace(topPrice, topAmount - executedAmount); } if (amount > 0) secondaryQueue.emplace(price, amount); } auto countTotalOrders = [](auto& queue) { long long total = 0; while (!queue.empty()) { total = (total + queue.top().second) % MOD; queue.pop(); } return total; }; return (countTotalOrders(buyOrders) + countTotalOrders(sellOrders)) % MOD; } }; Ставь 👍 и забирай 📚 Базу знаний
291
17
Задача: 641. Design Circular Deque Сложность: medium Разработайте свою реализацию круговой двусторонней очереди (deque). Реализуйте класс MyCircularDeque: MyCircularDeque(int k) Инициализирует deque с максимальным размером k. boolean insertFront() Добавляет элемент в переднюю часть Deque. Возвращает true, если операция прошла успешно, или false в противном случае. boolean insertLast() Добавляет элемент в заднюю часть Deque. Возвращает true, если операция выполнена успешно, или false в противном случае. boolean deleteFront() Удаляет элемент из передней части Deque. Возвращает true, если операция прошла успешно, или false в противном случае. boolean deleteLast() Удаляет элемент из задней части Deque. Возвращает true, если операция прошла успешно, или false в противном случае. int getFront() Возвращает передний элемент из Deque. Возвращает -1, если Deque пуст. int getRear() Возвращает последний элемент из Deque. Возвращает -1, если Deque пуст. boolean isEmpty() Возвращает true, если Deque пуст, или false в противном случае. boolean isFull() Возвращает true, если Deque полон, или false в противном случае. Пример: Input ["MyCircularDeque", "insertLast", "insertLast", "insertFront", "insertFront", "getRear", "isFull", "deleteLast", "insertFront", "getFront"] [[3], [1], [2], [3], [4], [], [], [], [4], []] Output [null, true, true, true, false, 2, true, true, true, 4] 👨‍💻 Алгоритм: 1⃣Инициализация и проверка состояний: Реализуйте конструктор для инициализации кольцевой двусторонней очереди заданного размера и методы для проверки пустоты и полноты очереди. 2⃣Операции вставки: Реализуйте методы вставки элементов в переднюю и заднюю части очереди с учетом кольцевой структуры. 3⃣Операции удаления: Реализуйте методы удаления элементов из передней и задней частей очереди с учетом кольцевой структуры и методы для получения переднего и заднего элементов очереди. 😎 Решение: class MyCircularDeque { public: MyCircularDeque(int k) : deque(k), front(0), rear(0), size(0), capacity(k) {} bool insertFront(int value) { if (isFull()) return false; front = (front - 1 + capacity) % capacity; deque[front] = value; size++; return true; } bool insertLast(int value) { if (isFull()) return false; deque[rear] = value; rear = (rear + 1) % capacity; size++; return true; } bool deleteFront() { if (isEmpty()) return false; front = (front + 1) % capacity; size--; return true; } bool deleteLast() { if (isEmpty()) return false; rear = (rear - 1 + capacity) % capacity; size--; return true; } int getFront() { if (isEmpty()) return -1; return deque[front]; } int getRear() { if (isEmpty()) return -1; return deque[(rear - 1 + capacity) % capacity]; } bool isEmpty() { return size == 0; } bool isFull() { return size == capacity; } private: vector<int> deque; int front; int rear; int size; int capacity; }; Ставь 👍 и забирай 📚 Базу знаний
338
18
Задача: 903. Valid Permutations for DI Sequence Сложность: hard Вам дана строка s длины n, где s[i] либо: 'D' означает убывание, либо 'I' означает возрастание. Перестановка perm из n + 1 целых чисел всех целых чисел в диапазоне [0, n] называется допустимой, если для всех допустимых i: если s[i] == 'D', то perm[i] > perm[i + 1], а если s[i] == 'I', то perm[i] < perm[i + 1]. Верните количество допустимых перестановок perm. Поскольку ответ может быть большим, верните его по модулю 109 + 7. Пример: Input: s = "DID" Output: 5 👨‍💻 Алгоритм: 1⃣Создать двумерный массив dp, где dp[i][j] представляет количество допустимых перестановок длины i, оканчивающихся на j. 2⃣Заполнить массив dp, учитывая условия возрастания и убывания из строки s. 3⃣Вернуть сумму dp[n][j] для всех j, что даст количество допустимых перестановок длины n + 1. 😎 Решение: class Solution { public: int numPermsDISequence(string s) { const int MOD = 1e9 + 7; int n = s.size(); vector<vector<int>> dp(n + 1, vector<int>(n + 1, 0)); dp[0][0] = 1; for (int i = 1; i <= n; i++) { for (int j = 0; j <= i; j++) { if (s[i - 1] == 'D') { for (int k = j; k < i; k++) { dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD; } } else { for (int k = 0; k < j; k++) { dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD; } } } } int result = 0; for (int j = 0; j <= n; j++) { result = (result + dp[n][j]) % MOD; } return result; } }; Ставь 👍 и забирай 📚 Базу знаний
322
19
Задача: 58. Length of Last Word Сложность: easy Дана строка s, состоящая из слов и пробелов. Верните длину последнего слова. Слово — это максимальная подстрока без пробелов. Пример: Input: s = "Hello World" Output: 5 👨‍💻 Алгоритм: 1⃣Идти с конца строки, пропуская пробелы, чтобы найти конец последнего слова 2⃣Затем считать символы до следующего пробела или начала строки — это и будет длина слова 3⃣Вернуть полученную длину 😎 Решение: class Solution { public: int lengthOfLastWord(string s) { int p = s.length() - 1; while (p >= 0 && s[p] == ' ') { p--; } int length = 0; while (p >= 0 && s[p] != ' ') { p--; length++; } return length; } }; Ставь 👍 и забирай 📚 Базу знаний
377
20
Задача: 846. Hand of Straights Сложность: medium У Алисы есть некоторое количество карт, и она хочет переставить карты в группы так, чтобы каждая группа была размером groupSize и состояла из groupSize последовательных карт. Дан целочисленный массив hand, где hand[i] — это значение, написанное на i-й карте, и целое число groupSize. Верните true, если она может переставить карты, или false в противном случае. Пример: Input: hand = [1,2,3,6,2,3,4,7,8], groupSize = 3 Output: true Explanation: Alice's hand can be rearranged as [1,2,3],[2,3,4],[6,7,8] 👨‍💻 Алгоритм: 1⃣Проверьте, делится ли длина массива hand на groupSize. Если нет, верните false. 2⃣Создайте карту cardCount для хранения количества каждой карты в массиве hand. 3⃣Итерируйте по массиву hand и обновляйте карту cardCount. Затем итерируйте снова для создания групп: Найдите начальную карту startCard для потенциальной последовательности, уменьшая startCard, пока не найдёте карту, которая отсутствует в карте cardCount. Попробуйте сформировать последовательность из groupSize карт, начиная с startCard. Если какая-либо карта в потенциальной последовательности отсутствует в карте cardCount, верните false. Если последовательность можно сформировать, уменьшите количество каждой карты в последовательности в карте cardCount. 😎 Решение: #include <vector> #include <unordered_map> #include <algorithm> using namespace std; class Solution { public: bool isNStraightHand(vector<int>& hand, int groupSize) { if (hand.size() % groupSize != 0) { return false; } unordered_map<int, int> cardCount; for (int card : hand) { cardCount[card]++; } sort(hand.begin(), hand.end()); for (int card : hand) { if (cardCount[card] == 0) { continue; } for (int nextCard = card; nextCard < card + groupSize; nextCard++) { if (cardCount[nextCard] == 0) { return false; } cardCount[nextCard]--; } } return true; } }; Ставь 👍 и забирай 📚 Базу знаний
328