Задача: 734. Sentence Similarity
Сложность: easy
Мы можем представить предложение в виде массива слов, например, предложение "I am happy with leetcode" можно представить как arr = ["I", "am",happy", "with", "leetcode"].
Даны два предложения sentence1 и sentence2, каждое из которых представлено в виде массива строк, и массив пар строк similarPairs, где similarPairs[i] = [xi, yi] указывает, что два слова xi и yi похожи. Возвращается true, если предложения sentence1 и sentence2 похожи, или false, если они не похожи. Два предложения похожи, если: у них одинаковая длина (т.е, Заметьте, что слово всегда похоже само на себя, также обратите внимание, что отношение сходства не является транзитивным. Например, если слова a и b похожи, а слова b и c похожи, то a и c не обязательно похожи.
Пример:
👨💻 Алгоритм:
1⃣ Проверьте, равны ли длины предложений sentence1 и sentence2. Если нет, верните false.
2⃣ Создайте словарь для хранения всех пар похожих слов.
3⃣ Проверьте каждую пару слов из предложений sentence1 и sentence2 на схожесть, используя словарь и правило, что слово всегда похоже на само себя.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Мы можем представить предложение в виде массива слов, например, предложение "I am happy with leetcode" можно представить как arr = ["I", "am",happy", "with", "leetcode"].
Даны два предложения sentence1 и sentence2, каждое из которых представлено в виде массива строк, и массив пар строк similarPairs, где similarPairs[i] = [xi, yi] указывает, что два слова xi и yi похожи. Возвращается true, если предложения sentence1 и sentence2 похожи, или false, если они не похожи. Два предложения похожи, если: у них одинаковая длина (т.е, Заметьте, что слово всегда похоже само на себя, также обратите внимание, что отношение сходства не является транзитивным. Например, если слова a и b похожи, а слова b и c похожи, то a и c не обязательно похожи.
Пример:
Input: sentence1 = ["great","acting","skills"], sentence2 = ["fine","drama","talent"], similarPairs = [["great","fine"],["drama","acting"],["skills","talent"]]
Output: true
class Solution {
public:
bool areSentencesSimilar(vector<string>& sentence1, vector<string>& sentence2, vector<vector<string>>& similarPairs) {
if (sentence1.size() != sentence2.size()) {
return false;
}
unordered_map<string, unordered_set<string>> similar;
for (const auto& pair : similarPairs) {
similar[pair[0]].insert(pair[1]);
similar[pair[1]].insert(pair[0]);
}
for (int i = 0; i < sentence1.size(); ++i) {
const string& w1 = sentence1[i];
const string& w2 = sentence2[i];
if (w1 != w2 && (similar[w1].find(w2) == similar[w1].end())) {
return false;
}
}
return true;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 979. Distribute Coins in Binary Tree
Сложность: medium
Вам дан корень бинарного дерева с n узлами, где каждый узел в дереве содержит node.val монет. Всего по всему дереву распределено n монет.
За один ход мы можем выбрать два смежных узла и переместить одну монету из одного узла в другой. Ход может быть как от родителя к ребенку, так и от ребенка к родителю.
Верните минимальное количество ходов, необходимых для того, чтобы каждый узел имел ровно одну монету.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и определение рекурсивной функции. Инициализируйте переменную moves = 0. Определите рекурсивную функцию dfs, которая считает количество перемещений монет. Базовый случай: если текущий узел равен null, верните 0.
2⃣ Рекурсивный обход дерева. Внутри dfs вызовите dfs для левого и правого поддеревьев, чтобы получить количество монет, которые нужно переместить в каждом поддереве. Вычислите количество перемещений для текущего узла: добавьте абсолютные значения перемещаемых монет в moves.
3⃣ Возвращение результата. Верните количество монет, которые текущий узел может передать своему родителю: значение узла плюс количество монет в левом и правом поддеревьях минус 1. Вызовите dfs от корня дерева и верните moves.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан корень бинарного дерева с n узлами, где каждый узел в дереве содержит node.val монет. Всего по всему дереву распределено n монет.
За один ход мы можем выбрать два смежных узла и переместить одну монету из одного узла в другой. Ход может быть как от родителя к ребенку, так и от ребенка к родителю.
Верните минимальное количество ходов, необходимых для того, чтобы каждый узел имел ровно одну монету.
Пример:
Input: root = [3,0,0]
Output: 2
Explanation: From the root of the tree, we move one coin to its left child, and one coin to its right child.
class Solution {
public:
int distributeCoins(TreeNode* root) {
moves = 0;
dfs(root);
return moves;
}
private:
int moves;
int dfs(TreeNode* current) {
if (current == nullptr) return 0;
int leftCoins = dfs(current->left);
int rightCoins = dfs(current->right);
moves += abs(leftCoins) + abs(rightCoins);
return current->val - 1 + leftCoins + rightCoins;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1103. Distribute Candies to People
Сложность: easy
Мы распределяем некоторое количество конфет ряду из n = num_people человек следующим образом:
Сначала даем 1 конфету первому человеку, 2 конфеты второму человеку и так далее, пока не дадим n конфет последнему человеку.
Затем мы возвращаемся к началу ряда, давая n + 1 конфету первому человеку, n + 2 конфеты второму человеку и так далее, пока не дадим 2 * n конфет последнему человеку.
Этот процесс повторяется (мы каждый раз даем на одну конфету больше и возвращаемся к началу ряда после достижения конца), пока у нас не закончатся конфеты. Последний человек получит все оставшиеся конфеты (не обязательно на одну больше, чем в предыдущий раз).
Верните массив (длиной num_people и суммой candies), который представляет собой окончательное распределение конфет.
Пример:
👨💻 Алгоритм:
1⃣ Вычислите количество людей, получивших полные подарки, и оставшиеся конфеты:
p = floor(sqrt(2C+0.25)-0.5)
remainig = C - p(p+1)/2
2⃣ Вычислите количество полных циклов и распределите конфеты:
rows = p // n
d[i]= i*rows + n*rows*(rows-1)/2
3⃣ Добавьте конфеты за дополнительный неполный цикл и оставшиеся конфеты:
d[i]+=i+n⋅rows для первых p%n людей
d[p%n]+=remaining
Верните распределение конфет d
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Мы распределяем некоторое количество конфет ряду из n = num_people человек следующим образом:
Сначала даем 1 конфету первому человеку, 2 конфеты второму человеку и так далее, пока не дадим n конфет последнему человеку.
Затем мы возвращаемся к началу ряда, давая n + 1 конфету первому человеку, n + 2 конфеты второму человеку и так далее, пока не дадим 2 * n конфет последнему человеку.
Этот процесс повторяется (мы каждый раз даем на одну конфету больше и возвращаемся к началу ряда после достижения конца), пока у нас не закончатся конфеты. Последний человек получит все оставшиеся конфеты (не обязательно на одну больше, чем в предыдущий раз).
Верните массив (длиной num_people и суммой candies), который представляет собой окончательное распределение конфет.
Пример:
Input: candies = 7, num_people = 4
Output: [1,2,3,1]
Explanation:
On the first turn, ans[0] += 1, and the array is [1,0,0,0].
On the second turn, ans[1] += 2, and the array is [1,2,0,0].
On the third turn, ans[2] += 3, and the array is [1,2,3,0].
On the fourth turn, ans[3] += 1 (because there is only one candy left), and the final array is [1,2,3,1].
p = floor(sqrt(2C+0.25)-0.5)
remainig = C - p(p+1)/2
rows = p // n
d[i]= i*rows + n*rows*(rows-1)/2
d[i]+=i+n⋅rows для первых p%n людей
d[p%n]+=remaining
Верните распределение конфет d
class Solution {
public:
vector<int> distributeCandies(int candies, int num_people) {
int n = num_people;
int p = int(sqrt(2 * candies + 0.25) - 0.5);
int remaining = candies - (p + 1) * p / 2;
int rows = p / n;
int cols = p % n;
vector<int> d(n, 0);
for (int i = 0; i < n; i++) {
d[i] = (i + 1) * rows + (rows * (rows - 1) / 2) * n;
if (i < cols) {
d[i] += i + 1 + rows * n;
}
}
d[cols] += remaining;
return d;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 400. Nth Digit
Сложность: medium
Дано целое число n, вернуть n-ю цифру бесконечной последовательности чисел [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...].
Пример:
👨💻 Алгоритм:
1⃣ Определение диапазона:
Начните с определения количества цифр в числах текущего диапазона (1-9, 10-99, 100-999 и т.д.).
Уменьшайте значение n, вычитая количество цифр в текущем диапазоне, пока не найдете диапазон, в который попадает n-я цифра.
2⃣ Нахождение конкретного числа:
Когда определите диапазон, найдите точное число, содержащее n-ю цифру.
Определите индекс цифры в этом числе.
3⃣ Возвращение n-й цифры:
Извлеките и верните n-ю цифру из найденного числа.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дано целое число n, вернуть n-ю цифру бесконечной последовательности чисел [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...].
Пример:
Input: n = 3
Output: 3
Начните с определения количества цифр в числах текущего диапазона (1-9, 10-99, 100-999 и т.д.).
Уменьшайте значение n, вычитая количество цифр в текущем диапазоне, пока не найдете диапазон, в который попадает n-я цифра.
Когда определите диапазон, найдите точное число, содержащее n-ю цифру.
Определите индекс цифры в этом числе.
Извлеките и верните n-ю цифру из найденного числа.
class Solution {
public:
int findNthDigit(int n) {
long length = 1, count = 9, start = 1;
while (n > length * count) {
n -= length * count;
length++;
count *= 10;
start *= 10;
}
start += (n - 1) / length;
string s = to_string(start);
return s[(n - 1) % length] - '0';
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1318. Minimum Flips to Make a OR b Equal to c
Сложность: medium
Даны три положительных числа a, b и c. Верните минимальное количество переворотов, необходимых в некоторых битах a и b, чтобы сделать (a OR b == c) (побитовая операция OR). Операция переворота состоит из изменения любого отдельного бита с 1 на 0 или с 0 на 1 в их двоичном представлении.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте переменную answer как 0, которая будет использоваться для отслеживания минимального количества необходимых переворотов.
2⃣ Итеративно обрабатывайте каждый бит двоичного представления чисел a, b и c одновременно:
Если (c & 1) == 0, обновите answer как answer += (a & 1) + (b & 1).
Если (c & 1) == 1, и если оба значения a & 1 и b & 1 равны 0, увеличьте answer на 1.
3⃣ Сдвигайте все числа вправо с помощью a >>= 1, b >>= 1, c >>= 1. Если все числа равны 0, верните answer, в противном случае, повторите шаги 2 и 3.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Даны три положительных числа a, b и c. Верните минимальное количество переворотов, необходимых в некоторых битах a и b, чтобы сделать (a OR b == c) (побитовая операция OR). Операция переворота состоит из изменения любого отдельного бита с 1 на 0 или с 0 на 1 в их двоичном представлении.
Пример:
Input: a = 2, b = 6, c = 5
Output: 3
Explanation: After flips a = 1 , b = 4 , c = 5 such that (a OR b == c)
Если (c & 1) == 0, обновите answer как answer += (a & 1) + (b & 1).
Если (c & 1) == 1, и если оба значения a & 1 и b & 1 равны 0, увеличьте answer на 1.
class Solution {
public:
int minFlips(int a, int b, int c) {
int answer = 0;
while (a != 0 || b != 0 || c != 0) {
if ((c & 1) == 1) {
if ((a & 1) == 0 && (b & 1) == 0) {
answer++;
}
} else {
answer += (a & 1) + (b & 1);
}
a >>= 1;
b >>= 1;
c >>= 1;
}
return answer;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 459. Repeated Substring Pattern
Сложность: easy
Дана строка s, проверьте, может ли она быть построена путем взятия подстроки и добавления нескольких копий этой подстроки друг за другом.
Пример:
👨💻 Алгоритм:
1⃣ Создайте целочисленную переменную n, равную длине строки s.
2⃣ Итерация по всем префиксным подстрокам длины i от 1 до n/2:
Если i делит n, объявите пустую строку pattern. Используйте внутренний цикл, который выполняется n/i раз для конкатенации подстроки, сформированной из первых i символов строки s.
Если pattern равен s, вернуть true.
3⃣ Если нет подстроки, которую можно повторить для формирования s, вернуть false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дана строка s, проверьте, может ли она быть построена путем взятия подстроки и добавления нескольких копий этой подстроки друг за другом.
Пример:
Input: heights = [2,1,5,6,2,3]
Output: 10
Explanation: The above is a histogram where width of each bar is 1.
The largest rectangle is shown in the red area, which has an area = 10 units.
Если i делит n, объявите пустую строку pattern. Используйте внутренний цикл, который выполняется n/i раз для конкатенации подстроки, сформированной из первых i символов строки s.
Если pattern равен s, вернуть true.
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int n = s.length();
for (int i = 1; i <= n / 2; i++) {
if (n % i == 0) {
string pattern = "";
for (int j = 0; j < n / i; j++) {
pattern += s.substr(0, i);
}
if (s == pattern) {
return true;
}
}
}
return false;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 290. Word Pattern
Сложность: easy
Дан шаблон из букв и строка, нужно определить, соответствует ли строка шаблону по правилу биекции между символами и словами.
Пример:
👨💻 Алгоритм
1⃣ Разделите строку s на слова, используя пробел как разделитель.
Проверьте, совпадает ли количество слов с длиной строки pattern. Если нет — верните false.
2⃣ Создайте два отображения:
mapChar: символ шаблона → слово
mapWord: слово → символ шаблона
3⃣ Итерируйтесь по шаблону и списку слов одновременно.
Если отображения нарушаются (несоответствие между буквой и словом) — верните false.
Если все соответствия верны — верните true.
😎 Решение
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дан шаблон из букв и строка, нужно определить, соответствует ли строка шаблону по правилу биекции между символами и словами.
Пример:
Input: pattern = "abba", s = "dog cat cat dog"
Output: true
Проверьте, совпадает ли количество слов с длиной строки pattern. Если нет — верните false.
mapChar: символ шаблона → слово
mapWord: слово → символ шаблона
Если отображения нарушаются (несоответствие между буквой и словом) — верните false.
Если все соответствия верны — верните true.
class Solution {
public:
bool wordPattern(string pattern, string s) {
unordered_map<char, string> mapChar;
unordered_map<string, char> mapWord;
vector<string> words;
stringstream ss(s);
string word;
while (ss >> word) {
words.push_back(word);
}
if (words.size() != pattern.size()) return false;
for (int i = 0; i < pattern.size(); ++i) {
char c = pattern[i];
string w = words[i];
if (mapChar.count(c)) {
if (mapChar[c] != w) return false;
} else {
if (mapWord.count(w)) return false;
mapChar[c] = w;
mapWord[w] = c;
}
}
return true;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 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, поэтому даже если в нем есть символы, которые могут быть разобраны как тег (корректный или некорректный), вы должны рассматривать их как обычные символы.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте стек для отслеживания открытых тегов и флаг для определения наличия тегов. Используйте регулярное выражение для проверки корректности TAG_NAME, TAG_CONTENT и CDATA.
2⃣ Пройдитесь по строке, проверяя каждый символ. Если встретите <, определите тип тега (начальный, конечный или CDATA). Обновите стек и индексы в зависимости от найденного типа.
3⃣ В конце проверьте, что стек пуст (все теги корректно закрыты) и верните результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: 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
#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();
}
};
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 38. Count and Say
Сложность: medium
Последовательность "Count and Say" строится по следующему принципу:
countAndSay(1) = "1"
countAndSay(n) — это строка, описывающая предыдущую строку (n−1), используя RLE (сжатие длиной серий), т.е. количество подряд идущих символов + сам символ.
Пример:
👨💻 Алгоритм:
1⃣ Начинаем с s = "1" как countAndSay(1).
2⃣ Для каждого шага до n применяем регулярное выражение, чтобы найти группы одинаковых подряд идущих символов.
3⃣ Для каждой группы записываем: длину группы + сам символ, формируя новую строку.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Последовательность "Count and Say" строится по следующему принципу:
countAndSay(1) = "1"
countAndSay(n) — это строка, описывающая предыдущую строку (n−1), используя RLE (сжатие длиной серий), т.е. количество подряд идущих символов + сам символ.
Пример:
Input: n = 4 Output: "1211"
class Solution {
public:
string countAndSay(int n) {
regex e("(.)\\1*");
string s = "1";
for (int i = 2; i <= n; i++) {
string t;
for (sregex_iterator it = sregex_iterator(s.begin(), s.end(), e);
it != sregex_iterator(); it++) {
t += to_string(it->str().size()) + it->str(1);
}
s = t;
}
return s;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1496. Path Crossing
Сложность: easy
Дана строка path, где path[i] = 'N', 'S', 'E' или 'W', каждая из которых представляет движение на одну единицу на север, юг, восток или запад соответственно. Вы начинаете с точки (0, 0) на 2D плоскости и идете по пути, указанному в path.
Верните true, если путь пересекает сам себя в какой-либо точке, то есть если вы в какой-то момент окажетесь в месте, которое уже посещали ранее. В противном случае верните false.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных:
Создать хэш-карту moves, которая сопоставляет символы 'N', 'S', 'E', 'W' с соответствующими значениями.
Инициализировать множество visited с начальной точкой (0, 0).
Установить начальные координаты x = 0 и y = 0.
2⃣ Проход по строке path:
Для каждого символа c в path получить значения (dx, dy) из moves[c].
Обновить координаты: добавить dx к x и dy к y.
Проверить, содержится ли текущая точка (x, y) в visited. Если да, вернуть true.
Добавить текущую точку (x, y) в visited.
3⃣ Возврат результата:
Если ни одна точка не пересекалась, вернуть false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дана строка path, где path[i] = 'N', 'S', 'E' или 'W', каждая из которых представляет движение на одну единицу на север, юг, восток или запад соответственно. Вы начинаете с точки (0, 0) на 2D плоскости и идете по пути, указанному в path.
Верните true, если путь пересекает сам себя в какой-либо точке, то есть если вы в какой-то момент окажетесь в месте, которое уже посещали ранее. В противном случае верните false.
Пример:
Input: path = "NESWW"
Output: true
Explanation: Notice that the path visits the origin twice.
Создать хэш-карту moves, которая сопоставляет символы 'N', 'S', 'E', 'W' с соответствующими значениями.
Инициализировать множество visited с начальной точкой (0, 0).
Установить начальные координаты x = 0 и y = 0.
Для каждого символа c в path получить значения (dx, dy) из moves[c].
Обновить координаты: добавить dx к x и dy к y.
Проверить, содержится ли текущая точка (x, y) в visited. Если да, вернуть true.
Добавить текущую точку (x, y) в visited.
Если ни одна точка не пересекалась, вернуть false.
class Solution {
public:
bool isPathCrossing(string path) {
unordered_map<char, pair<int, int>> moves = {
{'N', {0, 1}}, {'S', {0, -1}}, {'E', {1, 0}}, {'W', {-1, 0}}
};
set<pair<int, int>> visited = {{0, 0}};
int x = 0, y = 0;
for (char c : path) {
x += moves[c].first;
y += moves[c].second;
if (visited.count({x, y})) {
return true;
}
visited.insert({x, y});
}
return false;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1114. Print in Order
Сложность: easy
Предположим, у нас есть класс:
Один и тот же экземпляр Foo будет передан трем разным потокам. Поток A вызовет first(), поток B вызовет second(), и поток C вызовет third(). Спроектируйте механизм и модифицируйте программу, чтобы гарантировать, что second() выполняется после first(), а third() выполняется после second().
Примечание:
Мы не знаем, как потоки будут планироваться в операционной системе, даже если числа в вводе подразумевают порядок выполнения. Формат ввода, который вы видите, в основном предназначен для обеспечения полноты наших тестов.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных:
Инициализируйте координационные переменные firstJobDone и secondJobDone, чтобы указать, что задания еще не выполнены.
2⃣ Функция first():
В этой функции нет зависимости, поэтому можно сразу приступить к выполнению задания. В конце функции обновите переменную firstJobDone, чтобы указать, что первое задание выполнено.
3⃣ Функции second() и third():
В функции second() проверьте статус firstJobDone. Если она не обновлена, подождите, иначе переходите к выполнению второго задания. В конце функции обновите переменную secondJobDone, чтобы отметить завершение второго задания.
В функции third() проверьте статус secondJobDone. Аналогично функции second(), подождите сигнала secondJobDone перед тем, как приступить к выполнению третьего задания.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Предположим, у нас есть класс:
public class Foo {
public void first() { print("first"); }
public void second() { print("second"); }
public void third() { print("third"); }
}Один и тот же экземпляр Foo будет передан трем разным потокам. Поток A вызовет first(), поток B вызовет second(), и поток C вызовет third(). Спроектируйте механизм и модифицируйте программу, чтобы гарантировать, что second() выполняется после first(), а third() выполняется после second().
Примечание:
Мы не знаем, как потоки будут планироваться в операционной системе, даже если числа в вводе подразумевают порядок выполнения. Формат ввода, который вы видите, в основном предназначен для обеспечения полноты наших тестов.
Пример:
Input: nums = [1,2,3]
Output: "firstsecondthird"
Explanation: There are three threads being fired asynchronously. The input [1,2,3] means thread A calls first(), thread B calls second(), and thread C calls third(). "firstsecondthird" is the correct output.
Инициализируйте координационные переменные firstJobDone и secondJobDone, чтобы указать, что задания еще не выполнены.
В этой функции нет зависимости, поэтому можно сразу приступить к выполнению задания. В конце функции обновите переменную firstJobDone, чтобы указать, что первое задание выполнено.
В функции second() проверьте статус firstJobDone. Если она не обновлена, подождите, иначе переходите к выполнению второго задания. В конце функции обновите переменную secondJobDone, чтобы отметить завершение второго задания.
В функции third() проверьте статус secondJobDone. Аналогично функции second(), подождите сигнала secondJobDone перед тем, как приступить к выполнению третьего задания.
#include <semaphore.h>
#include <functional>
class Foo {
protected:
sem_t firstJobDone;
sem_t secondJobDone;
public:
Foo() {
sem_init(&firstJobDone, 0, 0);
sem_init(&secondJobDone, 0, 0);
}
void first(std::function<void()> printFirst) {
printFirst();
sem_post(&firstJobDone);
}
void second(std::function<void()> printSecond) {
sem_wait(&firstJobDone);
printSecond();
sem_post(&secondJobDone);
}
void third(std::function<void()> printThird) {
sem_wait(&secondJobDone);
printThird();
}
};
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 259. 3Sum Smaller
Сложность: medium
Дан массив целых чисел nums и число target. Нужно найти количество троек индексов i < j < k, таких что:
nums[i] + nums[j] + nums[k] < target.
Пример:
👨💻 Алгоритм:
1⃣ Отсортируйте массив nums по возрастанию, чтобы можно было применять бинарный поиск или двухуказательный подход.
2⃣ Для каждого i от 0 до n - 3, зафиксируйте nums[i], и найдите количество пар (j, k), таких что nums[i] + nums[j] + nums[k] < target.
3⃣ Для поиска количества пар, чья сумма меньше заданного порога, используйте бинарный поиск, чтобы найти максимальный возможный индекс k и посчитать количество допустимых комбинаций.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив целых чисел nums и число target. Нужно найти количество троек индексов i < j < k, таких что:
nums[i] + nums[j] + nums[k] < target.
Пример:
Input: nums = [-2,0,1,3], target = 2
Output: 2
Объяснение: Подходящие тройки: [-2,0,1], [-2,0,3]
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
int threeSumSmaller(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int sum = 0;
for (int i = 0; i < nums.size() - 2; i++) {
sum += twoSumSmaller(nums, i + 1, target - nums[i]);
}
return sum;
}
private:
int twoSumSmaller(vector<int>& nums, int startIndex, int target) {
int sum = 0;
for (int i = startIndex; i < nums.size() - 1; i++) {
int j = binarySearch(nums, i, target - nums[i]);
sum += j - i;
}
return sum;
}
int binarySearch(vector<int>& nums, int startIndex, int target) {
int left = startIndex;
int right = nums.size() - 1;
while (left < right) {
int mid = (left + right + 1) / 2;
if (nums[mid] < target) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
};
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 657. Robot Return to Origin
Сложность: easy
На плоскости с координатами (0, 0) находится робот. Дана последовательность его движений, определите, возвращается ли робот в исходную точку (0, 0) после завершения всех своих движений.
Вам дана строка moves, представляющая последовательность движений робота, где moves[i] представляет его i-ое движение. Допустимые движения: 'R' (вправо), 'L' (влево), 'U' (вверх) и 'D' (вниз).
Верните true, если робот возвращается в исходную точку после завершения всех своих движений, или false в противном случае.
Примечание: направление, в котором "смотрит" робот, не имеет значения. 'R' всегда будет перемещать робота на один шаг вправо, 'L' всегда будет перемещать его на один шаг влево и т.д. Также предполагается, что величина перемещения робота одинакова для каждого хода.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация координат:
Начните с координат (0, 0).
2⃣ Обработка движений:
Пройдите по строке moves и обновляйте координаты в зависимости от движения:
'R' увеличивает координату x на 1.
'L' уменьшает координату x на 1.
'U' увеличивает координату y на 1.
'D' уменьшает координату y на 1.
3⃣ Проверка конечных координат:
Если после всех движений координаты снова равны (0, 0), верните true. В противном случае, верните false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
На плоскости с координатами (0, 0) находится робот. Дана последовательность его движений, определите, возвращается ли робот в исходную точку (0, 0) после завершения всех своих движений.
Вам дана строка moves, представляющая последовательность движений робота, где moves[i] представляет его i-ое движение. Допустимые движения: 'R' (вправо), 'L' (влево), 'U' (вверх) и 'D' (вниз).
Верните true, если робот возвращается в исходную точку после завершения всех своих движений, или false в противном случае.
Примечание: направление, в котором "смотрит" робот, не имеет значения. 'R' всегда будет перемещать робота на один шаг вправо, 'L' всегда будет перемещать его на один шаг влево и т.д. Также предполагается, что величина перемещения робота одинакова для каждого хода.
Пример:
Input: moves = "UD"
Output: true
Начните с координат (0, 0).
Пройдите по строке moves и обновляйте координаты в зависимости от движения:
'R' увеличивает координату x на 1.
'L' уменьшает координату x на 1.
'U' увеличивает координату y на 1.
'D' уменьшает координату y на 1.
Если после всех движений координаты снова равны (0, 0), верните true. В противном случае, верните false.
class Solution {
public:
bool judgeCircle(string moves) {
int x = 0, y = 0;
for (char move : moves) {
switch (move) {
case 'R': x++; break;
case 'L': x--; break;
case 'U': y++; break;
case 'D': y--; break;
}
}
return x == 0 && y == 0;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 110. Balanced Binary Tree
Сложность: easy
Дано бинарное дерево. Определите, является ли оно сбалансированным по высоте.
Пример:
👨💻 Алгоритм:
1⃣ Определим функцию height, которая возвращает:
-1, если узел null;
1 + max(height(left), height(right)) — в остальных случаях.
2⃣ Проверим, что разность высот левого и правого поддеревьев не превышает 1.
3⃣ Рекурсивно проверим, что оба поддерева также сбалансированы:
если root == NULL — дерево сбалансировано (вернём true);
если разность высот больше 1 — вернём false;
иначе — вернём isBalanced(left) && isBalanced(right).
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дано бинарное дерево. Определите, является ли оно сбалансированным по высоте.
Пример:
Input: root = [3,9,20,null,null,15,7] Output: true
-1, если узел null;
1 + max(height(left), height(right)) — в остальных случаях.
если root == NULL — дерево сбалансировано (вернём true);
если разность высот больше 1 — вернём false;
иначе — вернём isBalanced(left) && isBalanced(right).
class Solution {
private:
int height(TreeNode* root) {
if (root == NULL) {
return -1;
}
return 1 + max(height(root->left), height(root->right));
}
public:
bool isBalanced(TreeNode* root) {
if (root == NULL) {
return true;
}
return abs(height(root->left) - height(root->right)) < 2 &&
isBalanced(root->left) && isBalanced(root->right);
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1150. Check If a Number Is Majority Element in a Sorted Array
Сложность: easy
Дан целочисленный массив nums, отсортированный в неубывающем порядке, и целое число target. Верните true, если target является элементом большинства, или false в противном случае.
Элемент большинства в массиве nums — это элемент, который встречается в массиве более чем nums.length / 2 раз.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменной count:
Инициализируйте переменную count значением 0..
2⃣ Итерация по списку nums:
Пройдите по каждому элементу списка nums.
Если элемент num равен target, увеличьте значение переменной count.
3⃣ Проверка условия мажоритарного элемента:
Если count больше чем половина длины списка nums, верните true.
В противном случае верните false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дан целочисленный массив nums, отсортированный в неубывающем порядке, и целое число target. Верните true, если target является элементом большинства, или false в противном случае.
Элемент большинства в массиве nums — это элемент, который встречается в массиве более чем nums.length / 2 раз.
Пример:
Input: nums = [2,4,5,5,5,5,5,6,6], target = 5
Output: true
Explanation: The value 5 appears 5 times and the length of the array is 9.
Thus, 5 is a majority element because 5 > 9/2 is true.
Инициализируйте переменную count значением 0..
Пройдите по каждому элементу списка nums.
Если элемент num равен target, увеличьте значение переменной count.
Если count больше чем половина длины списка nums, верните true.
В противном случае верните false.
class Solution {
public:
bool isMajorityElement(vector<int>& nums, int target) {
int count = 0;
for (int num : nums) {
if (num == target) {
count++;
}
}
return count > nums.size() / 2;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1263. Minimum Moves to Move a Box to Their Target Location
Сложность: hard
Кладовщик - это игра, в которой игрок перемещает коробки по складу, пытаясь доставить их в целевые места. Игра представлена сеткой символов m x n, где каждый элемент - это стена, пол или коробка. Ваша задача - переместить коробку "B" в целевую позицию "T" по следующим правилам: символ "S" представляет игрока. Игрок может перемещаться вверх, вниз, влево, вправо по сетке, если это пол (пустая клетка). Символ '.' обозначает пол, что означает свободную клетку для ходьбы. Символ '#' обозначает стену, что означает препятствие (туда невозможно пройти). В сетке есть только одна коробка 'B' и одна целевая клетка 'T'. Коробку можно переместить на соседнюю свободную клетку, стоя рядом с коробкой, а затем двигаясь в направлении коробки. Это толчок. Игрок не может пройти через коробку. Верните минимальное количество толчков, чтобы переместить коробку к цели. Если нет возможности добраться до цели, верните -1.
Пример:
👨💻 Алгоритм:
1⃣ Выполните поиск в ширину (BFS) для всех возможных позиций игрока и коробки, отслеживая количество толчков.
2⃣ Используйте очередь для хранения состояний игрока и коробки, а также текущего количества толчков.
3⃣ Для каждого состояния проверяйте все возможные движения игрока и перемещения коробки, обновляйте очередь и отмечайте посещенные состояния.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Кладовщик - это игра, в которой игрок перемещает коробки по складу, пытаясь доставить их в целевые места. Игра представлена сеткой символов m x n, где каждый элемент - это стена, пол или коробка. Ваша задача - переместить коробку "B" в целевую позицию "T" по следующим правилам: символ "S" представляет игрока. Игрок может перемещаться вверх, вниз, влево, вправо по сетке, если это пол (пустая клетка). Символ '.' обозначает пол, что означает свободную клетку для ходьбы. Символ '#' обозначает стену, что означает препятствие (туда невозможно пройти). В сетке есть только одна коробка 'B' и одна целевая клетка 'T'. Коробку можно переместить на соседнюю свободную клетку, стоя рядом с коробкой, а затем двигаясь в направлении коробки. Это толчок. Игрок не может пройти через коробку. Верните минимальное количество толчков, чтобы переместить коробку к цели. Если нет возможности добраться до цели, верните -1.
Пример:
Input: grid = [["#","#","#","#","#","#"],
["#","T","#","#","#","#"],
["#",".",".","B",".","#"],
["#",".","#","#",".","#"],
["#",".",".",".","S","#"],
["#","#","#","#","#","#"]]
Output: 3
class Solution {
public:
int minPushBox(vector<vector<char>>& grid) {
int m = grid.size(), n = grid[0].size();
vector<pair<int, int>> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
auto isValid = [&](int x, int y) {
return x >= 0 && x < m && y >= 0 && y < n && grid[x][y] != '#';
};
queue<tuple<int, int, int, int, int>> q;
unordered_set<string> visited;
int px, py, bx, by, tx, ty;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == 'S') {
px = i;
py = j;
} else if (grid[i][j] == 'B') {
bx = i;
by = j;
} else if (grid[i][j] == 'T') {
tx = i;
ty = j;
}
}
}
q.push({px, py, bx, by, 0});
visited.insert(to_string(px) + "," + to_string(py) + "," + to_string(bx) + "," + to_string(by));
while (!q.empty()) {
auto [px, py, bx, by, pushes] = q.front();
q.pop();
if (bx == tx && by == ty) {
return pushes;
}
for (auto [dx, dy] : directions) {
int npx = px + dx, npy = py + dy;
if (isValid(npx, npy)) {
if (npx == bx && npy == by) {
int nbx = bx + dx, nby = by + dy;
if (isValid(nbx, nby) && visited.insert(to_string(npx) + "," + to_string(npy) + "," + to_string(nbx) + "," + to_string(nby)).second) {
q.push({npx, npy, nbx, nby, pushes + 1});
}
} else if (visited.insert(to_string(npx) + "," + to_string(npy) + "," + to_string(bx) + "," + to_string(by)).second) {
q.push({npx, npy, bx, by, pushes});
}
}
}
}
return -1;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 73. Set Matrix Zeroes
Сложность: medium
Дана матрица m x n, нужно обнулить всю строку и столбец, если хотя бы один элемент равен 0.
Решение должно быть на месте, без использования дополнительной матрицы.
Пример:
👨💻 Алгоритм:
1⃣ Обход всей матрицы:
Если элемент matrix[i][j] == 0, помечаем:
matrix[0][j] = 0 (нужен обнулить весь столбец j)
matrix[i][0] = 0 (нужен обнулить всю строку i)
Первый столбец не может пересекаться с первой строкой → используем флаг isCol
2⃣ Второй проход (снизу вверх, слева направо):
Если matrix[i][0] == 0 или matrix[0][j] == 0, то matrix[i][j] = 0
3⃣ В конце отдельно обрабатываем первую строку и первый столбец:
Если matrix[0][0] == 0 → обнулить всю первую строку
Если isCol == true → обнулить весь первый столбец
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дана матрица m x n, нужно обнулить всю строку и столбец, если хотя бы один элемент равен 0.
Решение должно быть на месте, без использования дополнительной матрицы.
Пример:
Input: [[1,1,1],[1,0,1],[1,1,1]] Output: [[1,0,1],[0,0,0],[1,0,1]]
Если элемент matrix[i][j] == 0, помечаем:
matrix[0][j] = 0 (нужен обнулить весь столбец j)
matrix[i][0] = 0 (нужен обнулить всю строку i)
Первый столбец не может пересекаться с первой строкой → используем флаг isCol
Если matrix[i][0] == 0 или matrix[0][j] == 0, то matrix[i][j] = 0
Если matrix[0][0] == 0 → обнулить всю первую строку
Если isCol == true → обнулить весь первый столбец
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
bool isCol = false;
int R = matrix.size();
int C = matrix[0].size();
for (int i = 0; i < R; i++) {
if (matrix[i][0] == 0) {
isCol = true;
}
for (int j = 1; j < C; j++) {
if (matrix[i][j] == 0) {
matrix[0][j] = 0;
matrix[i][0] = 0;
}
}
}
for (int i = 1; i < R; i++) {
for (int j = 1; j < C; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
if (matrix[0][0] == 0) {
for (int j = 0; j < C; j++) {
matrix[0][j] = 0;
}
}
if (isCol) {
for (int i = 0; i < R; i++) {
matrix[i][0] = 0;
}
}
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 179. Largest Number
Сложность: medium
Дан список неотрицательных целых чисел nums. Организуйте их таким образом, чтобы они составляли наибольшее число и верните его.
Поскольку результат может быть очень большим, необходимо вернуть строку вместо целого числа.
Пример:
👨💻 Алгоритм:
1⃣ Преобразование и сортировка:
Преобразовать каждое число в строку и отсортировать массив строк по убыванию, используя компаратор, сравнивающий a + b и b + a.
2⃣ Проверка на нули:
Если после сортировки первый элемент равен "0", вернуть "0", так как все элементы — нули.
3⃣ Формирование результата:
Сконкатенировать отсортированные строки и вернуть
результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан список неотрицательных целых чисел nums. Организуйте их таким образом, чтобы они составляли наибольшее число и верните его.
Поскольку результат может быть очень большим, необходимо вернуть строку вместо целого числа.
Пример:
Input: nums = [10,2] Output: "210"
Преобразовать каждое число в строку и отсортировать массив строк по убыванию, используя компаратор, сравнивающий a + b и b + a.
Если после сортировки первый элемент равен "0", вернуть "0", так как все элементы — нули.
Сконкатенировать отсортированные строки и вернуть
результат.
cppКопироватьРедактироватьclass Solution {
public:
string largestNumber(vector<int> &nums) {
vector<string> strNums(nums.size());
for (int i = 0; i < nums.size(); ++i) {
strNums[i] = to_string(nums[i]);
}
sort(strNums.begin(), strNums.end(),
[](string &a, string &b) { return a + b > b + a; });
if (strNums[0] == "0") {
return "0";
}
string largestNumberStr;
for (string numAsStr : strNums) {
largestNumberStr += numAsStr;
}
return largestNumberStr;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 480. Sliding Window Median
Сложность: hard
Медиана — это среднее значение в упорядоченном списке целых чисел. Если размер списка четный, среднего значения не существует, поэтому медианой считается среднее значение двух средних чисел.
Например, если arr = [2, 3, 4], медиана равна 3.
Например, если arr = [1, 2, 3, 4], медиана равна (2 + 3) / 2 = 2.5.
Вам дан целочисленный массив nums и целое число k. Существует скользящее окно размера k, которое перемещается от самого левого края массива до самого правого. Вы можете видеть только k чисел в окне. Каждый раз скользящее окно перемещается вправо на одну позицию.
Верните массив медиан для каждого окна в исходном массиве. Ответы с точностью до 10^-5 будут приниматься.
Пример:
👨💻 Алгоритм:
1⃣ Сохраняйте числа в контейнере окна размера k, выполняя следующие операции: Вставка входящего элемента. Удаление выходящего элемента.
2⃣ Отсортируйте окно, чтобы найти медианы. Вместо того чтобы каждый раз копировать и сортировать k последовательных элементов из входных данных, вставляйте и удаляйте по одному элементу при каждом сдвиге окна.
3⃣ Поддерживайте окно в отсортированном состоянии до и после операций вставки и удаления.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Медиана — это среднее значение в упорядоченном списке целых чисел. Если размер списка четный, среднего значения не существует, поэтому медианой считается среднее значение двух средних чисел.
Например, если arr = [2, 3, 4], медиана равна 3.
Например, если arr = [1, 2, 3, 4], медиана равна (2 + 3) / 2 = 2.5.
Вам дан целочисленный массив nums и целое число k. Существует скользящее окно размера k, которое перемещается от самого левого края массива до самого правого. Вы можете видеть только k чисел в окне. Каждый раз скользящее окно перемещается вправо на одну позицию.
Верните массив медиан для каждого окна в исходном массиве. Ответы с точностью до 10^-5 будут приниматься.
Пример:
Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [1.00000,-1.00000,-1.00000,3.00000,5.00000,6.00000]
Explanation:
Window position Median
--------------- -----
[1 3 -1] -3 5 3 6 7 1
1 [3 -1 -3] 5 3 6 7 -1
1 3 [-1 -3 5] 3 6 7 -1
1 3 -1 [-3 5 3] 6 7 3
1 3 -1 -3 [5 3 6] 7 5
1 3 -1 -3 5 [3 6 7] 6
#include <vector>
#include <algorithm>
std::vector<double> medianSlidingWindow(std::vector<int>& nums, int k) {
std::vector<double> medians;
for (int i = 0; i + k <= nums.size(); i++) {
std::vector<int> window(nums.begin() + i, nums.begin() + i + k);
std::sort(window.begin(), window.end());
if (k % 2 == 1) {
medians.push_back(window[k / 2]);
} else {
medians.push_back((window[k / 2 - 1] + window[k / 2]) / 2.0);
}
}
return medians;
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 305. Number of Islands II
Сложность: hard
Дан пустой двумерный бинарный массив
Вы можете выполнить операцию "добавить землю", которая превращает воду в указанной позиции в сушу. Вам дан массив
Верните массив целых чисел
Остров окружен водой и образуется путем соединения соседних земель по горизонтали или вертикали. Вы можете считать, что все четыре края сетки окружены водой.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация
Создайте массивы x[] = { -1, 1, 0, 0 } и y[] = { 0, 0, -1, 1 }, которые будут использоваться для нахождения соседей ячейки.
Создайте экземпляр UnionFind, например, dsu(m * n). Инициализируйте всех родителей значением -1. Используйте объединение по рангу, инициализируйте все ранги значением 0. Наконец, инициализируйте count = 0.
Создайте список целых чисел answer, где answer[i] будет хранить количество островов, образованных после превращения ячейки positions[i] в сушу.
2⃣ Обработка позиций
Итерация по массиву positions. Для каждой позиции в positions:
Выполните линейное отображение, чтобы преобразовать двумерную позицию ячейки в landPosition = position[0] * n + position[1].
Используйте операцию addLand(landPosition), чтобы добавить landPosition как узел в граф. Эта функция также увеличит count.
Итерация по каждому соседу позиции. Соседа можно определить с помощью neighborX = position[0] + x[i] и neighborY = position[1] + y[i], где neighborX — координата X, а neighborY — координата Y соседней ячейки. Выполните линейное отображение соседней ячейки с помощью neighborPosition = neighborX * n + neighborY. Теперь, если на neighborPosition есть суша, т.е. isLand(neighborPosition) возвращает true, выполните объединение neighborPosition и landPosition. В объединении уменьшите count на 1.
3⃣ Определение количества островов
Выполните операцию numberOfIslands, которая возвращает количество островов, образованных после превращения позиции в сушу. Добавьте это значение в answer.
Верните answer.
😎 Решение
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дан пустой двумерный бинарный массив
grid размером m x n. Этот массив представляет собой карту, где 0 означает воду, а 1 — сушу. Изначально все ячейки массива — водные (т.е. все ячейки содержат 0).Вы можете выполнить операцию "добавить землю", которая превращает воду в указанной позиции в сушу. Вам дан массив
positions, где positions[i] = [ri, ci] — позиция (ri, ci), в которой следует выполнить i-ю операцию.Верните массив целых чисел
answer, где answer[i] — количество островов после превращения ячейки (ri, ci) в сушу.Остров окружен водой и образуется путем соединения соседних земель по горизонтали или вертикали. Вы можете считать, что все четыре края сетки окружены водой.
Пример:
Input: m = 1, n = 1, positions = [[0,0]]
Output: [1]
Создайте массивы x[] = { -1, 1, 0, 0 } и y[] = { 0, 0, -1, 1 }, которые будут использоваться для нахождения соседей ячейки.
Создайте экземпляр UnionFind, например, dsu(m * n). Инициализируйте всех родителей значением -1. Используйте объединение по рангу, инициализируйте все ранги значением 0. Наконец, инициализируйте count = 0.
Создайте список целых чисел answer, где answer[i] будет хранить количество островов, образованных после превращения ячейки positions[i] в сушу.
Итерация по массиву positions. Для каждой позиции в positions:
Выполните линейное отображение, чтобы преобразовать двумерную позицию ячейки в landPosition = position[0] * n + position[1].
Используйте операцию addLand(landPosition), чтобы добавить landPosition как узел в граф. Эта функция также увеличит count.
Итерация по каждому соседу позиции. Соседа можно определить с помощью neighborX = position[0] + x[i] и neighborY = position[1] + y[i], где neighborX — координата X, а neighborY — координата Y соседней ячейки. Выполните линейное отображение соседней ячейки с помощью neighborPosition = neighborX * n + neighborY. Теперь, если на neighborPosition есть суша, т.е. isLand(neighborPosition) возвращает true, выполните объединение neighborPosition и landPosition. В объединении уменьшите count на 1.
Выполните операцию numberOfIslands, которая возвращает количество островов, образованных после превращения позиции в сушу. Добавьте это значение в answer.
Верните answer.
class UnionFind {
vector<int> parent, rank; int count;
public:
UnionFind(int size) : parent(size, -1), rank(size, 0), count(0) {}
void addLand(int x) { if (parent[x] < 0) { parent[x] = x; count++; } }
bool isLand(int x) { return parent[x] >= 0; }
int numberOfIslands() { return count; }
int find(int x) { return parent[x] != x ? parent[x] = find(parent[x]) : x; }
void unionSet(int x, int y) { int xset = find(x), yset = find(y);
if (xset != yset) { if (rank[xset] < rank[yset]) parent[xset] = yset;
else { parent[yset] = xset; if (rank[xset] == rank[yset]) rank[xset]++; } count--; } }
};
class Solution {
public:
vector<int> numIslands2(int m, int n, vector<vector<int>>& positions) {
UnionFind dsu(m * n); vector<int> answer;
vector<int> x = {-1, 1, 0, 0}, y = {0, 0, -1, 1};
for (auto& pos : positions) {
int land = pos[0Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 636. Exclusive Time of Functions
Сложность: medium
На однопоточном процессоре выполняется программа, содержащая n функций. Каждая функция имеет уникальный ID от 0 до n-1. Вызовы функций хранятся в стеке вызовов: когда начинается вызов функции, ее ID заталкивается в стек, а когда вызов функции заканчивается, ее ID выгружается из стека. Функция, чей идентификатор находится в верхней части стека, является текущей выполняемой функцией. Каждый раз, когда функция запускается или завершается, мы пишем лог с идентификатором, началом или завершением и меткой времени. Вам предоставляется список logs, где logs[i] представляет собой i-е сообщение лога, отформатированное как строка "{function_id}:{"start" | "end"}:{timestamp}". Например, "0:start:3" означает, что вызов функции с идентификатором 0 начался в начале временной метки 3, а "1:end:2" означает, что вызов функции с идентификатором 1 завершился в конце временной метки 2. Обратите внимание, что функция может быть вызвана несколько раз, возможно, рекурсивно. Исключительное время функции - это сумма времен выполнения всех вызовов функции в программе. Например, если функция вызывается дважды, причем один вызов выполняется за 2 единицы времени, а другой - за 1 единицу, то эксклюзивное время равно 2 + 1 = 3. Верните эксклюзивное время каждой функции в массив, где значение по i-му индексу представляет собой эксклюзивное время для функции с идентификатором i.
Пример:
👨💻 Алгоритм:
1⃣ Парсинг логов: Пройдитесь по каждому логу, чтобы распознать действие (start или end) и идентификатор функции вместе с временной меткой.
2⃣ Использование стека: Используйте стек для отслеживания текущих вызовов функций. Если лог содержит start, добавьте функцию в стек и начните отсчет времени. Если лог содержит end, снимите функцию со стека и обновите эксклюзивное время.
3⃣ Обновление времени выполнения: Когда функция завершает выполнение, обновите ее эксклюзивное время и также учитывайте время выполнения вложенных функций.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
На однопоточном процессоре выполняется программа, содержащая n функций. Каждая функция имеет уникальный ID от 0 до n-1. Вызовы функций хранятся в стеке вызовов: когда начинается вызов функции, ее ID заталкивается в стек, а когда вызов функции заканчивается, ее ID выгружается из стека. Функция, чей идентификатор находится в верхней части стека, является текущей выполняемой функцией. Каждый раз, когда функция запускается или завершается, мы пишем лог с идентификатором, началом или завершением и меткой времени. Вам предоставляется список logs, где logs[i] представляет собой i-е сообщение лога, отформатированное как строка "{function_id}:{"start" | "end"}:{timestamp}". Например, "0:start:3" означает, что вызов функции с идентификатором 0 начался в начале временной метки 3, а "1:end:2" означает, что вызов функции с идентификатором 1 завершился в конце временной метки 2. Обратите внимание, что функция может быть вызвана несколько раз, возможно, рекурсивно. Исключительное время функции - это сумма времен выполнения всех вызовов функции в программе. Например, если функция вызывается дважды, причем один вызов выполняется за 2 единицы времени, а другой - за 1 единицу, то эксклюзивное время равно 2 + 1 = 3. Верните эксклюзивное время каждой функции в массив, где значение по i-му индексу представляет собой эксклюзивное время для функции с идентификатором i.
Пример:
Input: n = 2, logs = ["0:start:0","1:start:2","1:end:5","0:end:6"]
Output: [3,4]
class Solution {
public:
vector<int> exclusiveTime(int n, vector<string>& logs) {
stack<int> stack;
vector<int> times(n, 0);
int prevTime = 0;
for (const string& log : logs) {
stringstream ss(log);
string fidStr, type, timeStr;
getline(ss, fidStr, ':');
getline(ss, type, ':');
getline(ss, timeStr, ':');
int fid = stoi(fidStr);
int time = stoi(timeStr);
if (type == "start") {
if (!stack.empty()) {
times[stack.top()] += time - prevTime;
}
stack.push(fid);
prevTime = time;
} else {
times[stack.top()] += time - prevTime + 1;
stack.pop();
prevTime = time + 1;
}
}
return times;
}
};Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM