C/C++ | LeetCode
3.39K subscribers
153 photos
1.08K links
Cайт easyoffer.ru
Реклама @easyoffer_adv
ВП @easyoffer_vp

Тесты t.iss.one/+zYofcX2VLTM3MGMy
Вопросы собесов t.iss.one/+BTbqlW1VbIFmYmVi
Вакансии t.iss.one/+za2mJYs4riAzMzFi
Download Telegram
Задача: 986. Interval List Intersections
Сложность: 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: firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]
Output: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]


👨‍💻 Алгоритм:

1⃣Инициализация указателей:
Завести два указателя i и j, указывающие на начало firstList и secondList соответственно.

2⃣Поиск пересечений:
Пока оба указателя находятся в пределах своих списков, выполнить следующие действия:
Найти максимальное начало и минимальный конец текущих интервалов.
Если начало меньше или равно концу, добавить пересечение в результат.
Сдвинуть указатель списка, у которого текущий интервал заканчивается раньше.

3⃣Возврат результата:
Вернуть список пересечений.

😎 Решение:
class Solution {
public:
vector<vector<int>> intervalIntersection(vector<vector<int>>& firstList, vector<vector<int>>& secondList) {
vector<vector<int>> result;
int i = 0, j = 0;

while (i < firstList.size() && j < secondList.size()) {
int start = max(firstList[i][0], secondList[j][0]);
int end = min(firstList[i][1], secondList[j][1]);

if (start <= end) {
result.push_back({start, end});
}

if (firstList[i][1] < secondList[j][1]) {
i++;
} else {
j++;
}
}

return result;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1091. Shortest Path in Binary Matrix
Сложность: medium

Дан бинарный матричный массив grid размером n x n. Верните длину самого короткого чистого пути в матрице. Если чистого пути не существует, верните -1.

Чистый путь в бинарной матрице — это путь из верхнего левого угла (т.е. (0, 0)) в нижний правый угол (т.е. (n - 1, n - 1)), такой что:

Все посещенные клетки пути равны 0.
Все соседние клетки пути соединены по 8 направлениям (т.е. они различны и имеют общую сторону или угол).
Длина чистого пути — это количество посещенных клеток этого пути.

Пример:
Input: grid = [[0,1],[1,0]]
Output: 2


👨‍💻 Алгоритм:

1⃣Проверить, что начальная и конечная клетки открыты (равны 0). Если нет, вернуть -1.

2⃣Выполнить поиск в ширину (BFS) из начальной клетки, добавляя в очередь соседние клетки, если они открыты и еще не посещены. Обновлять длину пути для каждой клетки.

3⃣Если достигнута конечная клетка, вернуть длину пути. Если очередь пуста и конечная клетка не достигнута, вернуть -1.

😎 Решение:
#include <vector>
#include <queue>
using namespace std;

class Solution {
public:
int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
if (grid[0][0] != 0 || grid[grid.size() - 1][grid[0].size() - 1] != 0) {
return -1;
}

vector<vector<int>> directions = {
{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}
};

queue<pair<int, int>> q;
q.push({0, 0});
grid[0][0] = 1;

while (!q.empty()) {
auto [row, col] = q.front(); q.pop();
int distance = grid[row][col];
if (row == grid.size() - 1 && col == grid[0].size() - 1) {
return distance;
}
for (auto& direction : directions) {
int newRow = row + direction[0];
int newCol = col + direction[1];
if (newRow >= 0 && newCol >= 0 && newRow < grid.size() && newCol < grid[0].size() && grid[newRow][newCol] == 0) {
q.push({newRow, newCol});
grid[newRow][newCol] = distance + 1;
}
}
}
return -1;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Задача: 946. Validate Stack Sequences
Сложность: medium

Учитывая, что два целочисленных массива pushed и popped имеют разные значения, верните true, если это могло быть результатом последовательности операций push и pop на изначально пустом стеке, или false в противном случае.

Пример:
Input: pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
Output: true


👨‍💻 Алгоритм:

1⃣Инициализировать пустой стек.
Использовать указатель j для отслеживания текущей позиции в массиве popped.

2⃣Пройти по каждому элементу в массиве pushed:
Добавить элемент в стек.
Проверить верхний элемент стека:
Если он совпадает с текущим элементом в popped, удалить элемент из стека и увеличить указатель j.

3⃣В конце вернуть true, если указатель j достиг конца массива popped, иначе вернуть false.

😎 Решение:
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
stack<int> st;
int j = 0;
for (int x : pushed) {
st.push(x);
while (!st.empty() && j < popped.size() && st.top() == popped[j]) {
st.pop();
j++;
}
}
return j == popped.size();
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 729. My Calendar I
Сложность: medium

Вы создаете программу для использования в качестве календаря. Мы можем добавить новое событие, если его добавление не приведет к двойному бронированию. Двойное бронирование происходит, когда два события имеют некоторое непустое пересечение (т.е, Событие можно представить в виде пары целых чисел start и end, которая представляет собой бронирование на полуоткрытом интервале [start, end), диапазоне вещественных чисел x таких, что start <= x < end. Реализация класса MyCalendar: MyCalendar() Инициализирует объект календаря. boolean book(int start, int end) Возвращает true, если событие может быть успешно добавлено в календарь, не вызывая двойного бронирования. В противном случае возвращается false и событие не добавляется в календарь.

Пример:
Input
["MyCalendar", "book", "book", "book"]
[[], [10, 20], [15, 25], [20, 30]]
Output
[null, true, false, true]


👨‍💻 Алгоритм:

1⃣Создайте класс MyCalendar с инициализатором для хранения списка событий.

2⃣Реализуйте метод book(int start, int end) для проверки пересечения нового события с уже существующими событиями.

3⃣Если новое событие не пересекается с существующими событиями, добавьте его в список событий и верните true. В противном случае верните false.

😎 Решение:
class MyCalendar {
public:
MyCalendar() {}

bool book(int start, int end) {
for (const auto& event : events) {
if (start < event[1] && end > event[0]) {
return false;
}
}
events.push_back({start, end});
return true;
}

private:
vector<pair<int, int>> events;
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 257. Binary Tree Paths
Сложность: easy

Дано бинарное дерево. Нужно вернуть все возможные пути от корня до листьев, где путь представлен как строка вида "1->2->5".

Пример:
Input: root = [1,2,3,null,5]
Output: ["1->2->5","1->3"]

👨‍💻 Алгоритм:

1⃣Рекурсивный обход дерева
Если текущий узел не nullptr, добавляем его значение к строке path.

2⃣Проверка на лист
Если это лист (нет ни левого, ни правого потомка), добавляем текущий путь в список paths.

3⃣Обход дочерних узлов
Если узел не лист, продолжаем обход влево и вправо, дописывая "->" в строку пути.

😎 Решение:
class Solution {
public:
void construct_paths(TreeNode* root, string path, vector<string>& paths) {
if (root) {
path += to_string(root->val);
if (!root->left && !root->right) {
paths.push_back(path);
} else {
path += "->";
construct_paths(root->left, path, paths);
construct_paths(root->right, path, paths);
}
}
}

vector<string> binaryTreePaths(TreeNode* root) {
vector<string> paths;
construct_paths(root, "", paths);
return paths;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 650. 2 Keys Keyboard
Сложность: medium

На экране блокнота есть только один символ 'A'. Для каждого шага можно выполнить одну из двух операций над этим блокнотом: Copy All: скопировать все символы, присутствующие на экране (частичное копирование не допускается). Paste: Вы можете вставить символы, которые были скопированы в прошлый раз. Учитывая целое число n, верните минимальное количество операций, чтобы символ 'A' появился на экране ровно n раз.

Пример:
Input: n = 3
Output: 3


👨‍💻 Алгоритм:

1⃣Используйте динамическое программирование для отслеживания минимального количества операций, необходимых для достижения определенного количества 'A' на экране.

2⃣Итерируйтесь от 1 до n, проверяя все возможные делители текущего числа и обновляя минимальное количество операций для каждого числа.

3⃣Возвращайте значение из таблицы динамического программирования для n.

😎 Решение:
int minSteps(int n) {
if (n == 1) return 0;
vector<int> dp(n + 1, 0);
for (int i = 2; i <= n; ++i) {
dp[i] = i;
for (int j = 1; j <= i / 2; ++j) {
if (i % j == 0) {
dp[i] = min(dp[i], dp[j] + i / j);
}
}
}
return dp[n];
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1192. Critical Connections in a Network
Сложность: hard

Существует n серверов, пронумерованных от 0 до n - 1, соединенных неориентированными соединениями "сервер-сервер", образуя сеть, где connections[i] = [ai, bi] представляет собой соединение между серверами ai и bi. Любой сервер может достичь других серверов напрямую или косвенно через сеть.

Критическое соединение — это соединение, удаление которого сделает невозможным достижение некоторыми серверами других серверов.
Верните все критические соединения в сети в любом порядке.

Пример:
Input: n = 4, connections = [[0,1],[1,2],[2,0],[1,3]]
Output: [[1,3]]
Explanation: [[3,1]] is also accepted.


👨‍💻 Алгоритм:

1⃣Построение графа и инициализация:
Постройте граф в виде списка смежности и создайте словарь для хранения соединений.
Инициализируйте ранги для узлов.

2⃣Поиск в глубину (DFS):
Реализуйте функцию dfs для обхода графа.
Обновите ранги узлов и определите минимальный ранг для текущего узла.
Проверьте, можно ли удалить текущее соединение, и обновите минимальный ранг.

3⃣Поиск критических соединений:
После завершения обхода DFS преобразуйте оставшиеся соединения в список и верните его.

😎 Решение:
class Solution {
public:
vector<vector<int>> criticalConnections(int n, vector<vector<int>>& connections) {
formGraph(n, connections);
dfs(0, 0);

vector<vector<int>> result;
for (auto& conn : connDict) {
result.push_back({conn.first.first, conn.first.second});
}
return result;
}

private:
unordered_map<int, vector<int>> graph;
unordered_map<int, int> rank;
map<pair<int, int>, bool> connDict;

void formGraph(int n, vector<vector<int>>& connections) {
for (int i = 0; i < n; ++i) {
graph[i] = vector<int>();
rank[i] = -1;
}
for (auto& edge : connections) {
int u = edge[0], v = edge[1];
graph[u].push_back(v);
graph[v].push_back(u);
connDict[{min(u, v), max(u, v)}] = true;
}
}

int dfs(int node, int discoveryRank) {
if (rank[node] != -1) {
return rank[node];
}

rank[node] = discoveryRank;
int minRank = discoveryRank + 1;

for (int neighbor : graph[node]) {
if (rank[neighbor] != -1 && rank[neighbor] == discoveryRank - 1) {
continue;
}

int recursiveRank = dfs(neighbor, discoveryRank + 1);

if (recursiveRank <= discoveryRank) {
connDict.erase({min(node, neighbor), max(node, neighbor)});
}

minRank = min(minRank, recursiveRank);
}

return minRank;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1335. Minimum Difficulty of a Job Schedule
Сложность: hard

Вы хотите составить расписание списка заданий на d дней. Задания зависят друг от друга (т.е. чтобы выполнить задание i, вы должны закончить все задания j, где 0 <= j < i).

Вы должны выполнять как минимум одно задание каждый день. Сложность расписания заданий — это сумма сложностей каждого дня из d дней. Сложность дня — это максимальная сложность задания, выполненного в этот день.

Вам дан массив целых чисел jobDifficulty и целое число d. Сложность i-го задания равна jobDifficulty[i].

Верните минимальную сложность расписания заданий. Если вы не можете найти расписание для заданий, верните -1.

Пример:
Input: jobDifficulty = [6,5,4,3,2,1], d = 2
Output: 7
Explanation: First day you can finish the first 5 jobs, total difficulty = 6.
Second day you can finish the last job, total difficulty = 1.
The difficulty of the schedule = 6 + 1 = 7


👨‍💻 Алгоритм:

1⃣Определение состояния:
Индекс i (индекс первой задачи на сегодняшний день в массиве jobDifficulty) и день d (количество оставшихся дней) будут определять состояние динамического программирования. min_diff(i, d) обозначает минимальную сложность при начале с i-й задачи с оставшимися d днями. min_diff(0, d) будет окончательным ответом, так как он представляет начало с начала массива задач и завершение всех задач за ровно d дней.

2⃣Функция перехода состояния:
Задача с индексом j будет первой задачей на следующий день, следовательно, задачи, которые должны быть завершены сегодня, это все задачи с индексами между i и j, то есть jobDifficulty[i
]. Поскольку сложность дня — это максимальная сложность выполненной в этот день задачи, к сумме сложностей задач будет добавляться максимум из jobDifficulty[i
]. Формулируем функцию перехода состояния следующим образом: min_diff(i, d) = min_diff(j, d - 1) + max(jobDifficulty[i
]) для всех j > i.

3⃣Базовый случай:
Когда остается только 1 день, необходимо завершить все незавершенные задачи в этот день и увеличить сложность расписания задач на максимальную сложность этих задач.

😎 Решение:
class Solution {
public:
int minDifficulty(vector<int>& jobDifficulty, int d) {
int n = jobDifficulty.size();
if (n < d) {
return -1;
}

vector<vector<int>> mem(n, vector<int>(d + 1, -1));
return minDiff(0, d, jobDifficulty, mem);
}

private:
int minDiff(int i, int daysRemaining, vector<int>& jobDifficulty, vector<vector<int>>& mem) {
if (mem[i][daysRemaining] != -1) {
return mem[i][daysRemaining];
}

if (daysRemaining == 1) {
int res = 0;
for (int j = i; j < jobDifficulty.size(); j++) {
res = max(res, jobDifficulty[j]);
}
return res;
}

int res = INT_MAX;
int dailyMaxJobDiff = 0;
for (int j = i; j < jobDifficulty.size() - daysRemaining + 1; j++) {
dailyMaxJobDiff = max(dailyMaxJobDiff, jobDifficulty[j]);
res = min(res, dailyMaxJobDiff + minDiff(j + 1, daysRemaining - 1, jobDifficulty, mem));
}
mem[i][daysRemaining] = res;
return res;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 689. Maximum Sum of 3 Non-Overlapping Subarrays
Сложность: hard

Дан целочисленный массив nums и целое число k. Найдите три непересекающихся подмассива длины k с максимальной суммой и верните их.

Верните результат в виде списка индексов, представляющих начальную позицию каждого интервала (нумерация с 0). Если существует несколько ответов, верните лексикографически наименьший.

Пример:
Input: nums = [1,2,1,2,6,7,5,1], k = 2
Output: [0,3,5]
Explanation: Subarrays [1, 2], [2, 6], [7, 5] correspond to the starting indices [0, 3, 5].
We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically larger.


👨‍💻 Алгоритм:

1⃣Предположим, что фиксирован j. Нам нужно узнать на интервалах i∈[0,j−k] и l∈[j+k,len(W)−1], где наибольшее значение W[i] (и соответственно W[l]) встречается первым (то есть, с наименьшим индексом).

2⃣Мы можем решить эту задачу с помощью динамического программирования. Например, если мы знаем, что i - это место, где наибольшее значение W[i] встречается первым на [0,5], то на [0,6] первое появление наибольшего W[i] должно быть либо i, либо 6. Если, скажем, 6 лучше, тогда мы устанавливаем best = 6. В конце left[z] будет первым вхождением наибольшего значения W[i] на интервале i∈[0,z], а right[z] будет таким же, но на интервале i∈[z,len(W)−1].

3⃣Это означает, что для некоторого выбора j, кандидат на ответ должен быть (left[j - k], j, right[j + k]). Мы выбираем кандидата, который дает максимальное значение W[i] + W[j] + W[l].

😎 Решение:
class Solution {
public:
vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {
vector<int> W(nums.size() - k + 1);
int currSum = 0;
for (int i = 0; i < nums.size(); i++) {
currSum += nums[i];
if (i >= k) {
currSum -= nums[i - k];
}
if (i >= k - 1) {
W[i - k + 1] = currSum;
}
}

vector<int> left(W.size());
int best = 0;
for (int i = 0; i < W.size(); i++) {
if (W[i] > W[best]) best = i;
left[i] = best;
}

vector<int> right(W.size());
best = W.size() - 1;
for (int i = W.size() - 1; i >= 0; i--) {
if (W[i] >= W[best]) best = i;
right[i] = best;
}

vector<int> ans = {-1, -1, -1};
for (int j = k; j < W.size() - k; j++) {
int i = left[j - k], l = right[j + k];
if (ans[0] == -1 || W[i] + W[j] + W[l] > W[ans[0]] + W[ans[1]] + W[ans[2]]) {
ans = {i, j, l};
}
}
return ans;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 68. Text Justification
Сложность: hard

Дан массив слов words и ширина строки maxWidth. Необходимо вернуть текст, в котором строки выровнены по ширине с равномерным распределением пробелов, кроме последней строки — она выравнивается по левому краю.

Пример:
Input: words = ["This", "is", "an", "example", "of", "text", "justification."], maxWidth = 16
Output:
arduino[
"This is an",
"example of text",
"justification. "
]

👨‍💻 Алгоритм:

1⃣Разделить слова на строки: жадно добавлять слова, пока их суммарная длина + пробелы не превышают maxWidth

2⃣Создать строку с выравниванием:
если последняя строка или в строке одно слово — выравниваем по левому краю
иначе: равномерно распределяем пробелы между словами, остаток пробелов добавляется слева

3⃣Склеить строки и вернуть результат

😎 Решение:
class Solution {
public:
vector<string> fullJustify(vector<string>& words, int maxWidth) {
vector<string> ans;
int i = 0;
while (i < words.size()) {
vector<string> currentLine = getWords(i, words, maxWidth);
i += currentLine.size();
ans.push_back(createLine(currentLine, i, words, maxWidth));
}
return ans;
}

private:
vector<string> getWords(int i, vector<string>& words, int maxWidth) {
vector<string> currentLine;
int currLength = 0;
while (i < words.size() && currLength + words[i].size() <= maxWidth) {
currentLine.push_back(words[i]);
currLength += words[i].size() + 1;
i++;
}
return currentLine;
}

string createLine(vector<string>& line, int i, vector<string>& words, int maxWidth) {
int baseLength = -1;
for (const string& word : line) {
baseLength += word.size() + 1;
}
int extraSpaces = maxWidth - baseLength;

// Последняя строка или строка с одним словом
if (line.size() == 1 || i == words.size()) {
string res = join(line, " ");
res += string(extraSpaces, ' ');
return res;
}

int wordCount = line.size() - 1;
int spacesPerWord = extraSpaces / wordCount;
int needsExtraSpace = extraSpaces % wordCount;

for (int j = 0; j < needsExtraSpace; j++) {
line[j] += " ";
}
for (int j = 0; j < wordCount; j++) {
line[j] += string(spacesPerWord, ' ');
}

return join(line, " ");
}

string join(vector<string>& line, const string& delimeter) {
if (line.empty()) return "";
string res = line[0];
for (int i = 1; i < line.size(); i++) {
res += delimeter + line[i];
}
return res;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 244. Shortest Word Distance II
Сложность: medium

Необходимо реализовать структуру, которая быстро отвечает на запросы расстояния между двумя словами

Пример:
Input: ["WordDistance", "shortest", "shortest"] [[["practice", "makes", "perfect", "coding", "makes"]], ["coding", "practice"], ["makes", "coding"]] Output: [null, 3, 1]

👨‍💻 Алгоритм:

1⃣В конструкторе сохраняем словарь, где каждому слову сопоставляется список индексов, на которых оно встречается в массиве

2⃣При запросе shortest(word1, word2) получаем два списка индексов и двигаемся по ним двумя указателями, считая минимальное расстояние

3⃣Возвращаем минимальное абсолютное расстояние между индексами слов

😎 Решение:
#include <vector>
#include <string>
#include <unordered_map>
#include <algorithm>

class WordDistance {
public:
WordDistance(std::vector<std::string>& words) {
for (int i = 0; i < words.size(); ++i) {
locations[words[i]].push_back(i);
}
}

int shortest(std::string word1, std::string word2) {
const std::vector<int>& loc1 = locations[word1];
const std::vector<int>& loc2 = locations[word2];
int l1 = 0, l2 = 0, minDiff = INT_MAX;

while (l1 < loc1.size() && l2 < loc2.size()) {
minDiff = std::min(minDiff, std::abs(loc1[l1] - loc2[l2]));
if (loc1[l1] < loc2[l2]) {
++l1;
} else {
++l2;
}
}
return minDiff;
}

private:
std::unordered_map<std::string, std::vector<int>> locations;
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Задача: 476. Number Complement
Сложность: easy

Дополнение целого числа — это число, которое получается при замене всех 0 на 1 и всех 1 на 0 в его двоичном представлении.
Например, целое число 5 в двоичной системе — "101", и его дополнение — "010", что соответствует целому числу 2. Дано целое число num, верните его дополнение.

Пример:
Input: num = 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.

👨‍💻 Алгоритм:

1⃣Вычислите длину в битах входного числа: l=⌊log 2 (num)⌋+1.

2⃣Постройте битовую маску из 1-битов длины l: bitmask=(1≪l)−1.

3⃣Верните результат операции XOR числа и битовой маски: num⊕bitmask num⊕bitmask.

😎 Решение:
class Solution {
public:
int findComplement(int num) {
int bitmask = num;
bitmask |= (bitmask >> 1);
bitmask |= (bitmask >> 2);
bitmask |= (bitmask >> 4);
bitmask |= (bitmask >> 8);
bitmask |= (bitmask >> 16);
return bitmask ^ num;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 643. Maximum Average Subarray I
Сложность: easy

Вам дан целочисленный массив nums, состоящий из n элементов, и целое число k. Найдите смежный подмассив, длина которого равна k и который имеет максимальное среднее значение, и верните это значение. Принимается любой ответ с погрешностью вычислений менее 10-5.

Пример:
Input: nums = [1,12,-5,-6,50,3], k = 4
Output: 12.75000

👨‍💻 Алгоритм:

1⃣Инициализация скользящего окна: Вычислите сумму первых k элементов массива nums. Это будет начальное значение максимальной суммы.

2⃣Перемещение окна: Перемещайте окно длиной k по массиву, добавляя следующий элемент и убирая предыдущий, чтобы поддерживать сумму текущего окна.

3⃣Обновление максимальной суммы: На каждом шаге обновляйте максимальную сумму, если текущая сумма больше, и в конце верните среднее значение этой суммы.

😎 Решение:
class Solution {
public:
double findMaxAverage(vector<int>& nums, int k) {
int currentSum = accumulate(nums.begin(), nums.begin() + k, 0);
int maxSum = currentSum;

for (int i = k; i < nums.size(); i++) {
currentSum += nums[i] - nums[i - k];
maxSum = max(maxSum, currentSum);
}

return (double) maxSum / k;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 743. Network Delay Time
Сложность: medium

Дана сеть из узлов, помеченных от 1 до n. Также дано times - список времен прохождения сигнала в виде направленных ребер times[i] = (ui, vi, wi), где ui - исходный узел, vi - целевой узел, а wi - время прохождения сигнала от источника до цели. Мы пошлем сигнал из заданного узла k. Верните минимальное время, которое потребуется всем узлам, чтобы получить сигнал. Если все узлы не могут получить сигнал, верните -1.

Пример:
Input: times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Output: 2


👨‍💻 Алгоритм:

1⃣Представьте граф в виде списка смежности.

2⃣Используйте алгоритм Дейкстры для нахождения кратчайших путей от узла k до всех других узлов.

3⃣Найдите максимальное значение среди кратчайших путей к узлам. Если какой-либо узел недостижим, верните -1.

😎 Решение:
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int n, int k) {
unordered_map<int, vector<pair<int, int>>> graph;
for (int i = 1; i <= n; ++i) {
graph[i] = vector<pair<int, int>>();
}
for (auto& time : times) {
graph[time[0]].emplace_back(time[1], time[2]);
}

priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> minHeap;
minHeap.emplace(0, k);
unordered_map<int, int> minTime;
for (int i = 1; i <= n; ++i) {
minTime[i] = INT_MAX;
}
minTime[k] = 0;

while (!minHeap.empty()) {
auto [time, node] = minHeap.top(); minHeap.pop();
for (auto& [neighbor, t] : graph[node]) {
int newTime = time + t;
if (newTime < minTime[neighbor]) {
minTime[neighbor] = newTime;
minHeap.emplace(newTime, neighbor);
}
}
}

int maxTime = *max_element(minTime.begin(), minTime.end());
return maxTime == INT_MAX ? -1 : maxTime;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 96. Unique Binary Search Trees
Сложность: medium

Дано число n.
Нужно вычислить количество структурно уникальных бинарных деревьев поиска (BST),
состоящих из n узлов с уникальными значениями от 1 до n.

Пример:
Input: n = 3
Output: 5

👨‍💻 Алгоритм:

1⃣Обозначим G(n) — количество уникальных BST, построенных из n узлов.
Пусть F(i, n) — количество BST, в которых i является корнем.
Тогда:
G(n) = F(1, n) + F(2, n) + ... + F(n, n)

2⃣Для фиксированного i:
в левой части — i - 1 узел, в правой — n - i.
Т.е.
F(i, n) = G(i - 1) * G(n - i)

3⃣Тогда:
G(n) = ∑ G(i - 1) * G(n - i), i = 1..n
Сохраняем значения G[0] = 1 и G[1] = 1, и далее строим по формуле.

😎 Решение:
class Solution {
public:
int numTrees(int n) {
vector<int> G(n + 1, 0);
G[0] = 1;
G[1] = 1;

for (int i = 2; i <= n; ++i) {
for (int j = 1; j <= i; ++j) {
G[i] += G[j - 1] * G[i - j];
}
}

return G[n];
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 1005. Maximize Sum Of Array After K Negations
Сложность: easy

Учитывая целочисленный массив nums и целое число k, измените массив следующим образом: выберите индекс i и замените nums[i] на -nums[i]. Вы должны применить этот процесс ровно k раз. Вы можете выбрать один и тот же индекс i несколько раз. Верните наибольшую возможную сумму массива после его модификации таким образом.

Пример:
Input: nums = [4,2,3], k = 1
Output: 5


👨‍💻 Алгоритм:

1⃣Сортировка массива:
Отсортируйте массив nums по возрастанию, чтобы наибольшее количество раз менять самые маленькие (отрицательные) значения на их противоположные.

2⃣Модификация массива:
Пройдитесь по отсортированному массиву и замените k наименьших значений на их противоположные (умножьте на -1). Если встретите 0, прекратите дальнейшие изменения, так как изменение 0 на -0 не имеет смысла.

3⃣Проверка остатка изменений:
Если после первого прохода остались изменения (k нечетное), то найдите минимальное значение в измененном массиве и еще раз поменяйте его знак. Это обеспечит максимальную сумму.

😎 Решение:
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());

for (int i = 0; i < nums.size(); ++i) {
if (k > 0 && nums[i] < 0) {
nums[i] = -nums[i];
--k;
}
}

if (k % 2 == 1) {
sort(nums.begin(), nums.end());
nums[0] = -nums[0];
}

return accumulate(nums.begin(), nums.end(), 0);
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1063. Number of Valid Subarrays
Сложность: hard

Дан целочисленный массив nums. Вернуть количество непустых подмассивов, в которых левый элемент не больше других элементов подмассива.

Подмассив — это непрерывная часть массива.

Пример:
Input: nums = [1,4,2,5,3]
Output: 11
Explanation: There are 11 valid subarrays: [1],[4],[2],[5],[3],[1,4],[2,5],[1,4,2],[2,5,3],[1,4,2,5],[1,4,2,5,3].


👨‍💻 Алгоритм:

1⃣нициализируйте переменную ans значением 0. Инициализируйте пустой стек st, который будет хранить индексы элементов в стеке.

2⃣Итерируйте по элементам массива nums для каждого индекса i: продолжайте извлекать элементы из стека st, пока стек не станет пустым или элемент nums[i] не станет больше элемента на вершине стека. Для каждого извлеченного элемента добавляйте количество подмассивов как i - st.top(). Поместите текущий индекс i в стек.

3⃣Извлеките все оставшиеся элементы из стека и для каждого рассмотрите размер nums как индекс следующего меньшего элемента. Соответственно, добавьте nums.size() - st.top() к переменной ans. Верните ans.

😎 Решение:
class Solution {
public:
int validSubarrays(vector<int>& nums) {
int ans = 0;
stack<int> st;

for (int i = 0; i < nums.size(); i++) {
while (!st.empty() && nums[i] < nums[st.top()]) {
ans += (i - st.top());
st.pop();
}
st.push(i);
}

while (!st.empty()) {
ans += (nums.size() - st.top());
st.pop();
}

return ans;
}
};


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM